一.java继承
-
java不支持多继承即不能有多个父类。
-
使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况
-
final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写。被声明为 final 类的方法自动地声明为 final,但是实例变量并不是 final
-
子类不继承父类的构造函数,只是显示或隐式的调用。当父类构造函数含有参数时,子类构造函数必须通过super关键字进行显示调用父类构造函数(若不显式调用则系统会自动调用父类的无参构造函数);当父类构造函数无参时,子类构造函数中系统会自动调用父类的无参构造函数。
-
子类访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
-
重写: 声明为 static 的方法不能被重写,但是能够被再次声明。
子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法 -
重载: 重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
-
(6.7总结)
(1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。
(2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
(3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。 -
多态中的向上向下转型: (animal中只有eat方法,cat继承animal,且新加work方法)
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat)a; // 向下转型
c.work(); // 调用的是 Cat 的 work -
一个类只能继承extends一个抽象类,而一个类却可以实现implement多个接口
-
抽象类除了不能实例化对象之外(即不能new但可以声明对象)如果一个类包含抽象方法,那么该类必须是抽象类。任何子类必须重写父类的抽象方法。构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
-
抽象类和接口的区别
(1)抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
(2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
二.内部类,匿名对象
1.内部类
- 成员内部类
作为外部类的一个成员存在,与外部类的属性和方法并列
使用:内部类可以访问它的外部类的所有成员变量和方法,不管是静态的还是非静态的都可以。
在外部类里面创建成员内部类的实例:
this.new B();
在外部类之外创建内部类的实例:
(new Test1()).new B().go();
在内部类里访问外部类的成员:
Test1.this.member
class Out {
private int age = 12;
class In {
private int age = 13;
public void print() {
int age = 14;
System.out.println("局部变量:" + age);
System.out.println("内部类变量:" + this.age);
System.out.println("外部类变量:" + Out.this.age);
}
}
}
public class Demo {
public static void main(String[] args) {
Out.In in = new Out().new In();
in.print();
}
}
package memberiner;
public class Test1 {
private String member="这是外部类变量";
class B{ //成员内部类 ,不对外开放,高内聚
public B() {
//当内部类的构造器为Protected、private修饰时外部类外不可以访问
}
public void go(){
System.out.println("这是内部类B的go方法"+Test1.this.member);//内部类访问外部类变量
}
} //可供成员的外部类中其他方法调用
public B show(){
return this.new B();//外部类调用 ,是一个匿名对象
}
}
public class using{
public static void main(String[] args) {
B b = new Test1().show();
new Test1().show(); //匿名对象:声明一个实例但不将地址(引用)赋予某个对象
(new Test1()).new B().go();//外部类外访问内部类
}
}
2.方法内部类(局部内部类)
3.匿名内部类(局部内部类)
(1)匿名内部类就是没有名字的局部内部类,不使用关键字class, extends, implements, 没有构造方法。
(2)什么情况下需要使用匿名内部类?如果满足下面的一些条件,使用匿名内部类是比较合适的:
a·只用到类的一个实例。
b·类在定义后马上用到。
c·类非常小(SUN推荐是在4行代码以下)
d·给类命名并不会导致你的代码更容易被理解。
在使用匿名内部类时,要记住以下几个原则:
a·匿名内部类不能有构造方法。
b·匿名内部类不能定义任何静态成员、方法和类。
c·匿名内部类不能是public,protected,private,static。
d·只能创建匿名内部类的一个实例。
e·一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
f·因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。
(3)使用:
继承实现:
abstract class Person {
public abstract void eat();
}
class Child extends Person {
public void eat() {
System.out.println("eat something");
}
}
public class Demo {
public static void main(String[] args) {
Person p = new Child();
p.eat();
}
}
内部类实现:
abstract class Person {
public abstract void eat();
}
public class demo {
public static void main(String[] args) {
Person p= new Preson(){
public void eat(){
System.out.println("eat something");
}};
p.eat();
}
4.内部类引用外部类的成员变量和局部变量的区别
(1).内部类引用外部类局部变量时,外部类的局部变量一定要用final修饰。
因为为内部类和外部类的局部变量生命周期不一样,外部类方法执行完该局部变量可能会被释放掉,但该方法中的内部类可能还在执行(如线程),还要使用该变量,所以外部类变量设置为final的,变成常量,使用的时候内部类可以复制一个副本过去,相当于就不使用该局部变量了。
我们还可以从JVM的角度去解释这个现象,在编译期的时候,所有的类都会被编译成Class文件。内部类也会被编译成Class文件。但是上面的例子的内部类编译会和我们所知道的普通类编译方式会有些不同。
大多数的类在编译的时候,需要知道每个方法需要为其所有的局部变量分配多少内存。所以它会去检查方法内定义的变量,从而确定此方法到真正运行的时候需要在栈中开辟多少内存。但这只是计算需要多少内存,真正分配内存是在运行期。
所以当内部类使用外部类的局部变量时,在编译期也会给它分配额外的内存,并给它赋与外部类相等的值,但是此变量已经不是外部的局部变量了。在内存的角度上看,匿名内部类的i实际上不是外部的i,它们使用的内存空间都不同,只是它们的值相同。
其实本质上来说,完全可以当作两个不同的变量去使用,但是Java的设计人员可能想要保持一致性,因为Java的初学者在不了解其中真正的机制的时候,会以为他们就是同一个变量,所以干脆就把变量强制定义为final,这样变量就不能被重新赋值,营造一种他们是同一个变量的“假象”。
(2).内部类引用外部类的成员变量时,成员变量不一定要用final修饰,因为它不需要像上面说的那样要需在栈中重新开辟一个空间,而是内部类持有外部类的引用,可以使用外部类类名.this.变量名的方式