封装(Encapsulation)是面向对象的三大特征之一(另外两个是继承和多态),它指的是将对象的状态信息隐藏在对象内部,不容许外部程序直接访问对象内部信息,而是经过该类所提供的方法来实现对内部信息的操做和访问。java
Java 提供了 3 个访问控制符:private、 protected 和 public ,表明 3 种不一样的访问级别,再加上一个默认的访问控制级别(不使用任何访问控制符),共有 4 个访问控制级别。ide
private(当前类访问权限):类中的一个的成员被 private 修饰,它只能在当前类的内部被访问;函数
default(包访问权限):类中的一个成员或者一个外部类不使用任何访问控制符修饰,它能被当前包下其余类访问;this
protected(子类访问权限):类中的一个的成员被 protected 修饰,它既能够被当前包下的其余类访问,又能够被不一样包的子类访问;code
public(公共访问权限):类中的一个成员或者一个外部类使用 public 修饰,它能被全部类访问。对象
private | default | protected | public | |
---|---|---|---|---|
同一个类中 | ✔ | ✔ | ✔ | ✔ |
同一个包中 | ✔ | ✔ | ✔ | |
子类中 | ✔ | ✔ | ||
全局范围内 | ✔ |
java.lang.Object
,所以 java.lang.Object
是全部类的直接或间接父类。重写父类方法应遵循 “两同两小一大“ 规则:blog
class B { public void show() { System.out.println("B"); } } public class A extends B{ @Override public void show() { System.out.println("A"); //重写父类方法 } }
重载(Overload)和重写(Override)区别:继承
class B { private int x; public B(int x) { this.x = x; } public void show() { System.out.println("x:" + x); } } public class A extends B{ private int x; public A(int x, int x1) { super(x1); this.x = x; } @Override public void show() { super.show(); //调用被覆盖的父类方法 } public static void main(String[] args) { A a = new A(1, 2); a.show(); //x:2 } }
子类继承了父类的所有变量和方法,因此实例化子类时,必须先将其父类实例化。调用父类构造器的方式是 super(),参数为父类构造器所需参数。使用 super 调用父类构造器必须出现放在子类构造器的第一行,而 this 调用同一个类中重载的构造器也要放在第一行,因此 super() 和 this() 不能同时出现。get
无论是否使用 super 显式调用父类构造器,子类构造器总会调用父类构造器一次,总共会出现三种状况:io
多态:相同类型的变量调用同一个方法时呈现出多种不一样的行为特征。
产生缘由:Java 容许把一个子类对象直接赋给一个父类引用变量,无须任何类型转换。当把一个子类对象赋给父类引用变量时,会出现编译类型和运行类型不一致的状况,此时调用子类和父类的同名方法时(这里的同名指的是子类重写了父类方法),老是表现出子类方法的行为特征。例如:B b = new A()
编译类型看左边,运行类型看右边,所以编译类型为 B,运行类型为 A,当 b 调用 A 和 B 的同名的方法时,运行的老是 A 中的方法。
class B { public String book = "B"; public void base() { System.out.println("父类普通方法"); } public void test() { System.out.println("父类被覆盖的方法"); } public String getBook() { return book; } } public class A extends B{ public String book = "A"; @Override public void test() { System.out.println("子类覆盖父类方法"); } public void sub() { System.out.println("子类普通方法"); } @Override public String getBook() { return book; } public static void main(String[] args) { B b = new B(); System.out.println(b.book); //B b.base(); //父类普通方法 b.test(); //父类被覆盖的方法 System.out.println(b.getBook()); //B A a = new A(); System.out.println(a.book); //A a.base(); //父类普通方法 a.test(); //子类覆盖父类方法 System.out.println(a.getBook()); //A //编译看左边,运行看右边,编译和运行不一致 B b1 = new A(); //访问的是父类的属性,与方法不一样,实例变量不具备多态性 System.out.println(b1.book); //B //访问父类继承的方法 b1.base(); //父类普通方法 //访问的是子类的同名方法 b1.test(); //子类覆盖父类方法 //B没有提供sub()方法,就算A有,也没法经过编译 //b1.sub(); //错误 System.out.println(a.getBook()); //A } }
当代码运行 B b1 = new A()
时,编译类型为 B,运行类型为 A。
当调用 b1.test()
方法时(B 中有 test() 方法,A 中将其覆盖了),实际运行的是 A 的 test() 方法,方法行为老是表现出子类方法的行为特征,而不是父类方法的行为特征,这就是多态。
当执行 b1.base()
方法时,由于子类继承了父类的该方法,而且没有重写,因此运行一致。
当执行 b1.sub()
方法时,因为父类没有 sub() 方法,而编译时类型为父类,因此没法经过编译。
当执行 b1.book
获取同名实例变量时,返回的是父类的实例变量,与方法不一样,对象的实例变量则不具有多态性,返回的数据看编译时的类型。
当执行 b1.getBook()
方法时,实际运行的是 A 的 getBook() 方法 ,内部访问的实例变量是 A 的,方法是表现出多态特性。
注意:只有调用子类重写父类的方法才表现出多态性,直接访问公开的同名实例变量时不表现多态性,返回的数据看左边类型(编译类型)。