Java基础学习——面向对象思想

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基础学习——面向对象思想相关的知识,希望对你有一定的参考价值。

学习Java,就离不开学习面向对象的编程思想。Java语言是纯粹的面向对象的程序设计语言,这主要表现为Java完全支持面向对象的三种基本特征:

封装(encapsulation)

继承(inheritance)

多态(polymorphism)

Java语言完全以对象为中心,Java程序的最小程序单位是类,整个Java程序由一个一个的类组成。

万物皆对象

“面向对象”(英语:Object Oriented,简称OO)是一种以事物为中心的编程思想。

面向对象程序设计(英语:Object-oriented programming,缩写:OOP),是一种程序开发的方法。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。

面向对象时相对于面向过程而已的(c则是一个典型的面向过程的语言),站在面向对象的角度去看问题,你则是对象的动作的指挥者。如果站在面向过程的角度去看问题,你则是动作的执行者。

1.封装

为什么要封装?封装带来的好处是什么?下面以一个Person类来简述。

需求:1.描述一个Person类。定义姓名,性别的成员变量和PersonInfo的方法。

         2.创建一个Person对象,为其成员变量 赋值,调用其PersonInfo方法。

①无封装

 1 class Person 
 2 {
 3     String name;//姓名    
 4     String gender;//性别
 5     public void PersonInfo()
 6     {
 7         System.out.println("姓名:"+this.name+"性别:"+this.gender);
 8     }
 9 }
10 public class PersonDemo 
11 {
12 
13     public static void main(String[] args) 
14     {
15         //创建一个Person对象
16         Person jack=new Person();
17         jack.name="jack";
18         jack.gender="男";
19         jack.PersonInfo();//姓名:jack性别:男
20 
21         //传入非法参数
22         jack.gender="不是男人";
23         jack.PersonInfo();//姓名:jack性别:不是男人
24         
25     }
26 }

总结:如果不使用封装,很容易赋值错误,并且任何人都可以更改,造成数据的不安全

②封装

封装的实现:1:对外提供公开的用于设置对象属性的public方法

                  ----设置set

                  ----获取get

              2:在set方法中加入逻辑判断,过滤掉非法数据。

              3:将所有的成员变量封装加上private,提供get、set方法

 1 class Person 
 2 {
 3     private String name;//姓名    
 4     private String gender;//性别
 5     
 6     // 提供公有的get set方法
 7     public String getName() 
 8     {
 9         return name;
10     }
11     
12     public void setName(String n) 
13     {
14         name = n;
15     }
16     
17     public String getGender() 
18     {
19         return gender;
20     }
21         
22     public void setGender(String gen) 
23     {
24         if ("男".equals(gen) || "女".equals(gen))
25         {
26             gender = gen;
27             
28         } 
29         else 
30         {
31             System.out.println("请输入\"男\"或者\"女\"");
32 
33          }        
34     }
35 
36     public void PersonInfo()
37     {
38         System.out.println("姓名:"+this.name+"性别:"+this.gender);
39     }
40 }
41 public class PersonDemo 
42 {
43 
44     public static void main(String[] args) 
45     {
46         //创建一个Person对象
47         Person jack=new Person();
48         jack.setName("jack");
49         jack.setGender("男");
50         jack.PersonInfo();//姓名:jack性别:男
51 
52         //传入非法参数
53         jack.setGender("不是男人");
54         jack.PersonInfo();//无法传入
55         
56     }
57 }

可以看到实现封装之后,我们可以通过一定的手段来防止非法数据的污染,提高对象数据的安全性,并且可以隐藏类的具体实现。

2.继承

简单的说,继承就是在一个现有类型的基础上,通过增加新的方法或者重定义已有方法(下面会讲到,这种方式叫重写)的方式,产生一个新的类型。继承是面向对象的三个基本特征--封装、继承、多态的其中之一,我们在使用JAVA时编写的每一个类都是在继承,因为在JAVA语言中,java.lang.Object类是所有类最根本的基类(或者叫父类、超类),如果我们新定义的一个类没有明确地指定继承自哪个基类,那么JAVA就会默认为它是继承自Object类的。 

我们可以把JAVA中的类分为以下三种: 
      类:使用class定义且不含有抽象方法的类。
      抽象类:使用abstract class定义的类,它可以含有,也可以不含有抽象方法。
      接口:使用interface定义的类。 
在这三种类型之间存在下面的继承规律: 

①类可以继承(extends)类,可以继承(extends)抽象类,可以继承(implements)接口。
②抽象类可以继承(extends)类,可以继承(extends)抽象类,可以继承(implements)接口。`
③接口只能继承(extends)接口。 

类和抽象类都只能最多继承一个类,或者最多继承一个抽象类,并且这两种情况是互斥的,也就是说它们要么继承一个类,要么继承一个抽象类。
类、抽象类和接口在继承接口时,不受数量的约束,理论上可以继承无限多个接口。当然,对于类来说,它必须实现它所继承的所有接口中定义的全部方法。 

抽象类继承抽象类,或者实现接口时,可以部分、全部或者完全不实现父类抽象类的抽象(abstract)方法,或者父类接口中定义的接口。
类继承抽象类,或者实现接口时,必须全部实现父类抽象类的全部抽象(abstract)方法,或者父类接口中定义的全部接口。 

继承给我们的编程带来的好处就是对原有类的复用(重用)。

  1.子类继承父类的成员变量

  当子类继承了某个类之后,便可以使用父类中的成员变量,但是并不是完全继承父类的所有成员变量。具体的原则如下:

  1)能够继承父类的public和protected成员变量;不能够继承父类的private成员变量;

  2)对于父类的包访问权限成员变量,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能够继承;

  3)对于子类可以继承的父类成员变量,如果在子类中出现了同名称的成员变量,则会发生隐藏现象,即子类的成员变量会屏蔽掉父类的同名成员变量。如果要在子类中访问父类中同名成员变量,需要使用super关键字来进行引用。

  2.子类继承父类的方法

  1)能够继承父类的public和protected成员方法;不能够继承父类的private成员方法;

  2)对于父类的包访问权限成员方法,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能够继承;

  3)对于子类可以继承的父类成员方法,如果在子类中出现了同名称的成员方法,则称为覆盖,即子类的成员方法会覆盖掉父类的同名成员方法。如果要在子类中访问父类中同名成员方法,需要使用super关键字来进行引用。  

  3.构造器

  子类是不能够继承父类的构造器,但是要注意的是,如果父类的构造器都是带有参数的,则必须在子类的构造器中显示地通过super关键字调用父类的构造器并配以适当的参数列表。如果父类有无参构造器,则在子类的构造器中用super关键字调用父类构造器不是必须的,如果没有使用super关键字,系统会自动调用父类的无参构造器。

super关键字

需求:定义一个Son(子类)继承Father(父类)

 1 class Father {
 2     int x = 1;
 3 
 4     Father() {
 5         System.out.println("这是父类无参构造");
 6     }
 7 
 8     Father(int x) {
 9 
10         this.x = x;
11         System.out.println("这是父类有参构造");
12     }
13 
14     void speak() {
15         System.out.println("我是父亲");
16     }                  
17 }
18 
19 class Son extends Father {
20     int y = 1;
21 
22     Son() {
23         System.out.println("这是子类的无参构造");
24     }
25 
26     Son(int y) {
27 
28         this.y = y + x;
29         System.out.println("这是子类的有参构造");
30     }
31 
32     void run() {
33         super.speak(); // 访问父类的函数
34         System.out.println("我是儿子");
35     }
36 }
37 
38 class Demo{
39 
40     public static void main(String[] args) {
41         Son s = new Son(3);
42         System.out.println(s.y);// 4
43     }
44 }

 

super关键字作用

       1:主要存在于子类方法中,用于指向子类对象中父类对象。

       2:访问父类的属性

       3:访问父类的函数

       4:访问父类的构造函数

super注意

     1:this和super很像,this指向的是当前对象的调用,super指向的是当前调用对象的父类。

     2:子类的构造函数默认第一行会默认调用父类无参的构造函数,隐式语句

                          super();

           1:父类无参构造函数不存在,编译报错。

Son(int y) {
        //super();隐式语句
        this.y = y + x;
        System.out.println("这是子类的有参构造");
    }

 

      3:子类显式调用父类构造函数

          在子类构造函数第一行通过super关键字调用父类任何构造函数。如果显式调用父类构造函数,编译器自动添加的调用父类无参数的构造就消失。构造函数间的调用只能放在第一行,只能调用一次。super() 和this()不能同时存在构造函数第一行。

1 Son(int y) {
2         super(y);// 子类显式调用父类构造函数
3         this.y = y + x;
4         System.out.println("这是子类的有参构造");
5     }

重写(Override)

1:前提

    1)必须要有继承关系

2:特点

    1)当子类重写了父类的函数,那么子类的对象如果调用该函数,一定调用的是重写过后的函数。

       可以通过super关键字进行父类的重写函数的调用。

    2) 继承可以使得子类增强父类的方法

3:细节

    1) 函数名必须相同

    2)参数列表必须相同

    3)子类重写父类的函数的时候,函数的访问权限必须大于等于父类的函数的访问权限否则编译报错

    4)子类重写父类的函数的时候,返回值类型必须是父类函数的返回值类型或该返回值类型的子类

3.多态

从字面上理解,多态就是一种类型表现出多种状态。从一定角度来说,封装和继承是多态得以实现的基础。

多态前提:类与类之间有关系,继承父类或者实现接口。

多态体现

       1:父类引用变量指向了子类的对象

       2:父类引用也可以接受自己的子类对象

多态给我们带来的好处是消除了类之间的耦合关系,使程序更容易扩展。

一个简单的需求:用多态模拟  移动硬盘或者U盘或者MP3插到电脑上进行读写数据

 1 //抽象的父类
 2 abstract class MobileStorage
 3 {
 4  public abstract void Read();
 5  public abstract void Write();
 6 }
 7 
 8 class MobileDisk extends MobileStorage
 9 {
10  public void Read()
11  {
12      System.out.printf("移动硬盘在读取数据");
13  }
14  public  void Write()
15  {
16      System.out.printf("移动硬盘在写入数据");
17  }
18 }
19 class UDisk extends MobileStorage
20 {
21  public void Read()
22  {
23      System.out.printf("U盘在读取数据");
24  }
25 
26  public void Write()
27  {
28      System.out.printf("U盘在写入数据");
29  }
30 }
31 class Mp3 extends MobileStorage
32 {
33  public void Read()
34  {
35      System.out.printf("MP3在读取数据");
36  }
37 
38  public void Write()
39  {
40      System.out.printf("Mp3在写入数据");
41  }
42 
43  public void PlayMusic()
44  {
45      System.out.printf("MP3自己可以播放音乐");
46  }
47 }
48 
49 class Computer
50 {
51  MobileStorage Ms;
52 
53  public void CpuRead()
54  {
55      Ms.Read();
56  }
57 
58  public void CpuWrite()
59  {
60      Ms.Write();
61  }
62 }
63 
64 public class Demo {
65 
66     public static void main(String[] args) 
67     {
68          //类型提升,向上转型。new Mp3();//new MobileDisk();//new UDisk();
69          //但是不能使用子类的特有方法。
70          MobileStorage ms = new UDisk();         
71          Computer cpu = new Computer();      
72          cpu.Ms = ms;
73          cpu.CpuRead();
74          cpu.CpuWrite();
75          
76          //向下转型,可以强制将父类的引用转换成子类类型。    使用子类特有方法    
77          MobileStorage ms2=new Mp3();
78          if(ms2 instanceof Mp3)
79          {
80          Mp3 mp3=(Mp3)ms2;
81          mp3.PlayMusic();
82          }
83     }
84 
85 }

 

以上是关于Java基础学习——面向对象思想的主要内容,如果未能解决你的问题,请参考以下文章

Java01基础-07面向对象

DAY10-万物皆对象-2018-2-2

Java学习之路:面向对象

java基础

JAVA编程思想学习笔记——第一章 对象导论

JAVA编程思想学习笔记——第一章 对象导论