10.11学习笔记
今天学习了《Java编程思想》的第十章—内部类的前半部分。下面对今天学习收获与疑惑作一个总结。
①内部类与外部类的联系:
当生成一个非静态内部类的对象时,此对象必定会秘密的捕获一个指向那个外围类对象的引用,非静态内部类的对象正是使用这个引用来访问外部类的所有成员。因此,在创建一个非静态内部类的对象时,必须要使用外部类对象的引用,有两种方法获取外部类对象的引用:外部类名字.this 和 new一个外部类对象,所以外部类名字.this = 外部类对象的引用。创建内部类时,就要使用这个外部类的对象引用.new 一个内部类对象。
②静态内部类与非静态内部类:
非静态内部类:
初始化:非静态内部类相当于外部类的一个方法,因此,非静态内部类是在外部类加载完成之后自动加载的。
调用外部类元素:非静态内部类可以访问外部类所有的成员,外部类也可以访问内部类的所有成员变量(包括private方法,不过要创建一个内部类对象)。
自己成员、方法:非静态内部类不允许声明static成员变量和方法,因为java虚拟机要求:所有的静态变量必须在所有的非静态变量加载完成之前载入内存之中。对于非静态内部类,外部类加载完所有的静态成员,然后加载内部类,最后才加载内部类中的静态成员,显然不满足java虚拟机的要求。
静态内部类:
初始化:静态内部类不需要对外部类对象的引用,静态类和方法时属于类本身,并不属于该类的对象。外部类不会自动加载静态内部类,只有调用到静态内部类的成员变量或者方法时,才会将静态内部类加载入内存。
调用外部元素:静态内部类只能访问外部类static方法和数据域。
自己的成员、方法:没有限制,可以声明静态的,也可以声明非静态的。
无论是静态内部类还是非静态内部类,都会被编译成内部类的个数 + 1 个class文件。
/*
attention:Outer经编译后产生两个class文件(外部类名字$内部类名字($内部类名字).class)
*/
public class Outer {
int a = 0;
private static int b;
class Inner{
//非静态内部类可以访问外部类的所有域
public int getA(){
return a;
}
public int getB(){
return b;
}
}
public Inner getInner(){
return new Inner();
}
//静态内部类
static class staticInner{
//静态内部类只能访问外部类的static域
/**
public int getA(){
return a; //无法访问非static域
}*/
public int getB(){
return b;
}
}
public static void main(String args[]){
Outer outer = new Outer();
Outer.Inner inner = outer.getInner();
//Outer.Inner inner1 = new Inner() 编译器报错
Outer.Inner inner1 = outer.new Inner();//使用外部类的对象.new 可以创建一个内部类对象
Outer.staticInner staticInner = new staticInner();//静态内部类的创建不需要引用外部类的对象
}
}
③内部类与向上转型(现在还不理解其左右,只知道可以封装一个类的实现):
通过将内部类向上转型为一个接口的时候,可以完全隐藏实现的细节。
public interface First {
void description();
}
public class Second {
private class Inner implements First {
@Override
public void description(){
System.out.println("fuQian");
}
}
public First getFirst(){ //通过Second类返回一个内部类的对象
return new Inner();
}
}
public class Third extends Second {
public static void main(String args[]){
Second second = new Second();
second.getFirst().description(); //通过向上转型为接口,可以访问到内部类,所以完全隐藏了内部类的实现细节
//second.new Inner Inner类声明为private,没有任何人可以访问他
}
}
通过内部类将Inner设置为private(普通的类只能声明为public或者默认的包内访问),因此所有人都不能访问它,除非调用getFirst()方法返回一个Inner对象,从而完全隐藏了实现的细节。
④在方法和作用域内使用内部类:
public interface A {
public void test();
}
public class B{
public A getA(){
class Inner implements A{
@Override
public void test(){
System.out.println("肤浅");
}
}
return new Inner();
}
public static void main(String args[]){
B b = new B();
b.getA().test();
}
}
在getA()方法内创建了一个内部类并实现了A接口。
剩下的内部类内容,明天再学习吧。