Java 3大特性
9. Encapsulation, Inheritance, Polymorphism
1.encapsulation:
-
Methods:完成某个独立功能的代码。
-
Classes:封装了某个事物的属性和行为。
eg:
1.1生活中封装的案例:
电脑机箱就是一个封装体,里面包含:主板、电源、cpu、硬盘、显卡、内存、风扇等。
问题:电脑如果没有主机箱,只是把这些不同的设备临时组装,可以使用吗? 可以正常使用,但不安全。
怎么解决这些不安全因素?
把电脑中的各种硬盘设备全部封装到了一机箱内,而对外提供一些可以访问机箱内部设备的接口(例:USB、电源按键)
1.2benefit of encapsulation:
封装可以隐藏事物的细节(提高了安全性)。它把不需要外界直接操作的细节隐藏起来,然后通过第三方的按钮或者接口等手段保证外界还可以间接的去使用这些被隐藏起来的组件。
2、封装可以提高程序中代码的复用性和阅读性。(比如函数和类)
1.3 get/set method
不能直接操作属性,通过get/set方法可以控制输入的值得合法性。
1.4 this keyword
指向当前类的地址。
当局部变量和成员变量重名时,就需要使用this关键字来区别成员变量和局部变量
1.5 构造方法
-
用于创建对象,并对对象初始化。调用方法: 类名 + 对象名= new 类名();// *类名()相当于默认构造方法。
-
普通方法无法调用构造方法。
-
构造方法可以重载。
-
构造方法包括:无参构造方法,有参构造方法,全参构造方法。
-
当我们书写一个类的时候,如果在这个类中如果不写任何的构造函数,那么javac编译时会自动的添加一个无参构造函数。
-
2.inheritance:
Inheritance: 子类继承父类,获得父类中所有的非私有化的属性和方法。
2.1 @override:
- 方法名一致,参数类型一致,
- 返回值的范围必须小于等于父类的范围
- 子类方法的权限必须大于等于父类的范围。public>protected>(default)>private.
2.2 构造方法:
- 可以通过super()来调用父类的重载构造。
- super keyword: 指向父类的指针,类比this.
- super()关键字必须在子类构造方法的第一行。
- 子类构造方法中,如果没有super(),在编译时,首行会默认添加有一个super()(这是父类无参构造方法), 然后执行子类构造方法。
- java 是单继承,多级继承的。
2.3 Keyword abstract
抽象类的作用:能够限制,提醒子类必须实现某些功能。
- Abstract method must be defined in abstract classes. usually all the abstract methods must be overriden by child class, unless the child class is also an abstract class.
public abstract class xxx{int i;public abstract void fun();//abstract method: no method contextspublic int plus(){ //method contexts }// normal method
}
- the abstract classes cannot be instantiated directly. We can only instantiate an child-class object which has already overriden the abstract method.
- 抽象方法一定存在于抽象类中,抽象类不一定包含抽象方法。
- 抽象类中的构造方法是供子类创建对象时,初始化父类属性使用。
- abstract 与final ,static,private 不能共存。
2.4 Interface
1、接口是多个类公共的规范标准。接口是一个引用数据类型。对不同类的事物中,相同的功能进行抽取。
2、如何定义一个接口,如下:
public interface name{//接口内容//public abstract void test();
}
3、接口内容有:
- java7: 成员变量(默认被public static final 修饰,相当于常量),抽象方法(默认 public abstract修饰),如下
public interface name{//接口内容//public static final int MAX = 10;//成员变量,必须赋值。//public abstract void test();//抽象方法
}
- java8: 默认方法(为了接口升级,在接口中新增一个方法,而不用更改该接口的实现类(实现类必须重写接口中的所有抽象方法))如下
public interface name{//接口内容//public default void test(){//方法体};}
静态方法: 可以直接调用(调用形式: Interface.method(); )
public interface name{//接口内容//public static void test(){方法体};}
-
java9及以上: 私有方法(只有自己能够调用): 私有默认方法,(注意没有default)
public interface name{public default void test1(){print(AA);common;}public default void test2(){print(BB);common();}//private void common(){print(这是AB共有的内容);}}
私有静态方法
public interface name{public static void test1(){print(AA);common;}public static void test2(){print(BB);common();}//private static void common(){print(这是AB共有的内容);}}
接口中的方法的权限修饰符默认都是public abstract …
2.4、接口的使用步骤:
-
定义出接口
-
接口没有构造方法(因为接口中只有常量和抽象方法,常量在方法区,方法必须被实现类重写,接口方法所需要的变量在实现类中也都已经有了,所以不需要构造方法。),不能直接创建接口的对象
-
类似抽象类,接口必须有一个实现类来实现(override)该接口。(实现类的命名一般为 interface_Impl)
public class name implements interface{//类体}
-
接口的实现类必须重写接口中的所有抽象方法
-
创建实现类的对象,进行使用
总结: 接口可以给不同类的事物,扩展相同的功能。
-
2.5 interface and father-class
- 一个实现类的父类只有一个,而它的接口可以有很多个,用逗号隔开。
- 如果多个接口有相同的方法,只需要重写一个抽象方法就行了。
- 如果多个接口有相同的默认方法,必须重写一个方法。
- 如果父类和接口中有相同的方法,父类优先。
- 接口和接口直接可以继承多个父接口,如果父接口间有相同的抽象方法,无所谓;如果父接口间有相同的默认方法,子接口必须重写该默认方法,成为自己的默认方法。
3.polymorphism:
父类 对象名= new 子类(); //父类引用指向子类对象 // 接口 对象名 = new 实现类;接口引用指向实现类对象
创建一个子类对象,把它当做父类看待来使用,向上转型,这样一定是安全的。
eg: Father_class father = new Child_class();
在堆中开辟的是子类对象空间, “father” 是一个指向该开辟的该子类空间的指针。
多态必须满足三要素,继承,对象的向上转型(父类引用指向子类对象),重写
-
如果父类和子类中有相同的成员变量,成员变量的值与等号左边所属类中的变量保持一致,如果没有,则再向上找,也就是父类中找?此例中,father.成员变量, father 被当做父类来看待,所以选择父类中的成员变量值。口诀:(编译看左边,运行还是看左边)
public class Fu {int age=99; }public class Zi extends Fu {int age=1; } public class Test {public static void main(String[] args) {Fu father= new Zi();System.out.println(father.age);//the result is 99} }
-
如果父类和子类有相同的方法,看new 的是谁,用谁的方法,没有则向上找。此例中new 的是子类,调用的是Child_class 中的方法。口诀(编译看左,运行看右: 如果一个方法子类和父类都有,运行子类方法,如果一个方法父类中有,子类没有,编译不报错,运行时子类没有该方法,向上找,在父类中找到方法并运行; 如果一个方法父类没有,子类有,编译时会报错。father.method 找不到该方法。)解决办法:
将该对象还原为原本的子类,格式(类似强制类型转换): Child_class father_backto_child = (Child_class) father
注意,不能将其转为其他的子类,运行时会报错。
eg:
class Father{protected int age;public Father(){age = 40;} void eat(){System.out.println("父亲在吃饭");}
}class Child extends Father{protected int age;public Child(){age = 18;} void eat(){System.out.println("孩子在吃饭");}void play(){System.out.println("孩子在打CS");}
}public class TestPolymorphic {public static void main(String[] args) {Father c = new Child();c.eat();//result :孩子在吃饭//c.play(); // c.play() cannot be compiledSystem.out.println("年龄:"+c.age );//age is 40}}
the out print is :
Result:当满足Java多态的三个条件时,可以发现c.eat()调用的实际上是子类的eat,但c.age调用的却是是父类的age,而子类特有方法c.play()则不会通过编译。