封装(Encapsulation)是面向对象的三大特征之一(另外两个是继承和多态),它指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。
Java 提供了 3 个访问控制符:private、 protected 和 public ,代表 3 种不同的访问级别,再加上一个默认的访问控制级别(不使用任何访问控制符),共有 4 个访问控制级别。
default(包访问权限):类中的一个成员或者一个外部类不使用任何访问控制符修饰,它能被当前包下其他类访问;
public(公共访问权限):类中的一个成员或者一个外部类使用 public 修饰,它能被所有类访问。
private | default | protected | public | |
---|---|---|---|---|
同一个类中 | ? | ? | ? | ? |
同一个包中 | ? | ? | ? | |
子类中 | ? | ? | ||
全局范围内 | ? |
java.lang.Object
,因此 java.lang.Object
是所有类的直接或间接父类。重写父类方法应遵循 “两同两小一大“ 规则:
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()
不能同时出现。
不管是否使用 super 显式调用父类构造器,子类构造器总会调用父类构造器一次,总共会出现三种情况:
多态:相同类型的变量调用同一个方法时呈现出多种不同的行为特征。
产生原因: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 的,方法是表现出多态特性。
注意:只有调用子类重写父类的方法才表现出多态性,直接访问公开的同名实例变量时不表现多态性,返回的数据看左边类型(编译类型)。
原文:https://www.cnblogs.com/zongmin/p/11342221.html