多态总结
1. 什么是子父类的继承关系, 特点是什么?
a. 继承描述的是类与类的一种关系, 父类中描述的是所有继承子类所有的共性信息, 子类是父类的一个延续
b. 父类包含了一类事物的功能, 继承使子类无需自己创建就可直接获得这些功能
c. 继承只能是单继承, 因为当多个父类中拥有多个同名方法时, 就不知道用那个方法了
d. 而且, 如果有多级继承, 继承来的方法是直接父类的方法
e. 不可以在静态函数中使用 this/super关键字
2. 继承中, 子父类的成员变量是什么关系?
a. 子类自动得到父类的可访问变量, 即, 如未覆盖, 子类this引用自动指向父类的成员变量, 父类中的私有变量是得不到的
b. 内存中, 会先加载父类.class文件, 子父类同名的成员变量同时在内存中, 一个被this本类引用指向, 一个被super父类引用指向
c. 如果一定要调用父类的变量需要通过父类引用super.member来实现; 而a中情况,this,super指向内存中同一个继承来的变量
//成员变量的关系
class First{
public String str="First str"; // --> 2.b
public String strF="strF"; // --> 2.a
}
class Second extends First{
public String str="Second str"; // --> 2.b
public String strCompare="this.str="+super.str+"\nsuper.str="+this.str+"\ns.str="+str;
// --> 2.b,c
}
public class ExtendsDemo{
public static void main(String[] args){
Second s=new Second();
System.out.println(s.strF);
System.out.println(s.strCompare);
// System.out.println(this.str); // --> 1.e
// System.out.println(super.str); // --> 1.e
}
}
输出:strF
this.str=First str
super.str=Second str
s.str=Second str
3. 继承中,子父类的方法是什么关系?
a. 子父类中一样的函数是复写关系
b. 复写的好处是, 避免了修改源码的过程, 通过继承老的类, 复写需要修改的方法
c. 复写时需要调用父类被复写方法的代码: method(){super.method();}
d. 子类复写父类, 需要保证子类的权限大于等于父类的权限
e. 静态只能复写静态
//成员方法的关系
class First{
public void show(){
System.out.println("First's show");
}
public void firstOnly(){
System.out.println("First"); // --> 3.b
}
public void show0(){}; // --> 3.d
public static void fee(){}; // --> 3.e
}
class Second extends First{
public void show(){
System.out.println("Second's show");
}
// void show0(){}; // --> 3.d
// public void fee(){}; // --> 3.e
public void showFirst(){
super.show(); // --> 3.c
}
}
public class ExtendsDemo{
public static void main(String[] args){
Second s=new Second();
s.firstOnly(); // --> First
s.show(); // --> Second's show
s.showFirst(); // --> First's show
}
}
4. 复写和重载的区别?
a. 复写的同名方法一定要子父类中一模一样
b. 重写的同名方法必须要求方法的参数列表不同
c. 只有返回类型值不同的方法是不容许定义的
5. 继承中,子父类的构造函数是什么关系?
a. 子类在加载时, 其构造函数上(无论是空否)都有一个隐式的super(); 相当于先加载父类的空构造函数,再加州本类的构造函数
b. 如果父类不存在空的构造函数,子类的构造函数中必须指定加载一个父类的构造函数
c. 总之, 子类必然要访问一个父类的构造函数,而且super()语句要写在子类构造函数的第一行
d. 复写时, 子类要调用本来构造方法, 用 this(), 而且也必须出现在第一行, 考虑c, 即复写时只能出现this()/super()其中一个
//构造函数的关系
class First{
public First(){
System.out.println("First run");
}
public First(String str){
System.out.println("Frist("+str+") run");
}
}
class Second extends First{
public Second(){ // --> 5.a
System.out.println("Second run");
}
public Second(String str){ // --> 5.a
System.out.println("Second("+str+") run");
}
public Second(int num){
super("second(num)"); // --> 5.b,c
// 上一行替换为this(); // --> 5.d
System.out.println("Second("+num+") run");
}
}
public class ExtendsDemo{
public static void main(String[] args){
new Second(); // --> First run Second run
new Second("a"); // --> First run Second("a") run
new Second(1); // --> First(second(num)) run Second(1) run
}
}
6. 为什么子类一定要加载父类的构造函数?
a. 构造函数可能接受一些成员初始化的值, 子类的成员可能需要依赖这些成员的初始化值
7. final关键字在类, 变量, 方法上分别是怎么用的, 定义成final的用处是什么?
a. 被final修饰的类不可以被继承, 可以避免用户通过一个子类继承的方式来改变这个类的所有属性
b. 被final修饰的方法不可以被子类复写, 给用户继承的权利,但是不可以改变某些方法的输出属性
c. 被final修饰的变量是一个常量,只能被赋值一次, 既可以修饰成员变量又可以修饰局部变量, 为了增强不可变数据的安全性
d. 内部类定义在类中的局部位置上时,只能访问局部被final修饰的局部变量
8. 抽象方法/类是什么, 有什么特点, 为什么要定义抽象?
a. 抽象方法是一种同类型(具体实现不同或不确定的)方法的抽取, 没有代码体, 不可以用new创建对象, 调用它也没有意义
b. 有抽象方法要被实用,必须由子类复写起所有的抽象方法后, 建立子类的对象调用
c. 抽象类是包含有抽象方法的类, 这其实是一种表示, 表明此类有需要复写内部的抽象方法
d. 如果一个抽象类的子类没有复写父类抽象类中所有的抽象方法, 那么这个子类还是一个抽象类
e. 抽象类可以没有一个抽象方法, 这样做的唯一一个目的就是不让这个类实例化
9. 接口是什么, 接口有什么特点?
a. 接口是将一些类所共有的方法抽取成一个功能描述的类, 所有子类可以实现这个接口中的方法以表征这个接口定义的功能,
b. 接口定义了一类事物一种规则, 实现是一种规则的遵循;
c. 接口在定义上可以理解为一个只包含常量(public static final)和/或抽象方法(public abstract)的抽象类
d. 接口中所有的成员都是public的
e. 接口中默认包含 public static final 和 public abstract关键字
f. 类与接口的关系叫implements, 一个类/接口可以implements多个接口
g. 接口于接口的关系还叫extends, 一个接口可以extends多个接口(注意,多个父接口中不可以有只有返回值不同的方法)
h. 接口不可以创建对象, 如果要实例化, 必须有一个可以实现此接口中所有方法的子实现类
// 接口示例
interface A{void methodA();} // --> 9.e
interface B{void methodB();} // --> 9.e
interface C extends A,B{void methodC();} // --> 9.g
interface D{
public abstract void methodD(); // --> 9.c,d
public static final double PI=3.14; // --> 9.c,d
}
public class ImplementsDemo implements C1,D1 { // --> 9.f
public void methodA(){};
public void methodB(){};
public void methodC(){};
public void methodD(){};
public static void main(String[] args) {
System.out.println(new ImplementsDemo().PI); // --> 9.h
}
}
10. 什么是多态, 多态的好处是?
a. 多态可以是一类事物在不同分类,场合,的不同角色的体现, 这些角色的体现包含再该事物的继承和实现体系之中
b. 一个子类事物,可以作为一个父类或父接口的的角色被识别和接受, 即父类的引用接受了自己的子类对象
c. 多态的出现大大的提高了程序的可扩展性, 特别是体现在对方法参数的引用类型的向上装换上面
d. c的方法会牺牲子类的本类特殊功能的调用, 如果希望调用子类特殊功能, 需要进行向下类型转换(需要判断instanceof)
e. 虽然c在引用调用方法时收的引用类(父类)可见方法的限制, 调用的方法的仍然是对象中的方法(即子类中复写的方法体)
f. e的另一种说法是: 多态非静态方法编译时期看引用, 运行时期看对象;
g. 静态方法/静态成员/非静态成员多态时无论编译和运行都只看引用;
//多态示例
abstract class Animal{
abstract public void eat();
public void sleep(){System.out.println("Zzz");};
}
class Cat extends Animal{
public void eat(){System.out.println("Fish");}
public void catchMouse(){System.out.println("Catch Mouse");}
}
class Dog extends Animal{
public void eat(){System.out.println("Bone");}
public void guardHouse(){System.out.println("Guard House");}
}
public class PolymorphismDemo {
public static void main(String[] args) {
doSomething(new Cat());
doSomething(new Dog());
}
public static void doSomething(Animal a){
a.eat();
if(a instanceof Cat) // --> 10.d,e
((Cat) a).catchMouse();
if(a instanceof Dog) // --> 10.d,e
((Dog) a).guardHouse();
a.sleep();
}
}
11. instanceof关键字如何理解?
a. instanceof 用来判断一个引用名称的对象是否是一个类的对象,父类的子类对象或者接口的子类实现
b. 无论引用是父类还是接口, 只看这个引用对用的对象
interface Man{} class Father{}
class Son extends Father implements Man{}
public class InstanceofTest {
public static void main(String[] args) {
Son son=new Son(); // --> 11.a
Father son1=new Son(); // --> 11.b
Man son2=new Son(); // --> 11.b
System.out.println((son instanceof Son)+"," // --> true,true,true
+(son instanceof Father)+","+(son instanceof Man));
System.out.println((son1 instanceof Son)+"," // --> true,true,true
+(son1 instanceof Father)+","+(son1 instanceof Man));
System.out.println((son2 instanceof Son)+"," // --> true,true,true
+(son2 instanceof Father)+","+(son2 instanceof Man));
}
}
12. 内部类是什么, 有什么特点, 如何在内部类中调用外部类的成员, 如何在内部类调用外部类的成员?
a. 内部类是一个定义在一个类中的类, 内部类可以访问外部类中的成员包括私有
b. 外部类如果要访问内部类, 需要建立内部类对象
c. 内部类是一个类内部的成员,所以可以被多种修饰符修饰, 如 private, static
13. 如何在其他类中直接访问一个类的内部类中的成员, 如何区分内部类和外部类的同名成员?
a. 同样也需要建立一个内部类对象: OuterName.InnerName oi= new OuterName().new InnerName();
b. 一个有内部类的类有这样几个引用: 局部成员 x; 内部类成员: this.x 外部类成员: OuterName.this.x
c. 本类中访问会省略this或OuterName.this, 查找顺序是: 先检查局部, 在检查内部类引用, 再检查外部类引用, 先找到哪个就返回哪个值
//内部类示例
class Outer{
int x=1; // --> 13.b Outer.this.
class Inner{
int x=2; // --> 13.b this.
void show(){
int x=3;
System.out.println(x+" "+this.x+" "+Outer.this.x);
} // --> 13.c
}
}
public class InnerTest {
public static void main(String[] args) {
Outer.Inner oi=new Outer().new Inner(); // --> 13.a
oi.show();
}
}
14. 内部类定义成static的时候有哪些要注意的?
a. static:内部类具有static特性;当内部类被static修饰后,只能访问外部类中static成员,出现访问局限。
b. 在外部其他类中,访问static内部类成员:new Outer.Inner().function(); //外部类名调用静态成员=>新建对象=>调用方法
c. 在外部其他类中,访问static内部static成员:new Outer.Inner.function();
d. 当内部类定义了static成员,内部类必须是static的(static部分先于外部类对象存在)
e. 当外部类中的static方法访问内部类时,内部类也必须是static; (static的外部类方法调用不需要对象,只有调用static的内部类才能被调用)
15. 局部内部类有哪些要注意的?
a. 不可以被成员修饰符修饰;
b. 可以直接访问外部类的成员,因为还持有外部类的引用;
c. 不可以访问它所在的局部中的变量,除非这个局部变量被final修饰
// 静态和局部内部类示例
class Outer{
static int x=1; // --> 14.a
static class Inner{ // --> 14.d,e
void show(){ // --> 14.b
System.out.println(x);
}
static void staticShow(){};
} // --> 14.c
void fee(){
//int x=0; // --> 15.c 无法通过编译 需要final
class InnerLocal{ // --> 15.a
void foo(){
System.out.println(x);
} // --> 15.b
}
}
}
public class InnerTest {
public static void main(String[] args) {
Outer.Inner oi=new Outer.Inner(); // --> 15.b
oi.show();
Outer.Inner.staticShow(); // --> 15.c
}
}
参考资料: 传智博客毕老师Java基础视频