Java_内部类

内部类的好处:提供更好地封装和方便访问外部类的私有成员。


1. 非静态内部类

public class Temp {	
	public static void main (String args[]) {
		Outer outer = new Outer();
		outer.print();
	}
}

class Outer{
	private String name = "Outer class";
	public String getName() {
		return this.name;
	}
	public void print() {
		new Inner().printInfo();
	}
	private class Inner{
		private String name = "Inner class";
		public void printInfo(){
			System.out.println(this.name);	//访问本类成员
			System.out.println(Outer.this.name);	//访问外部类成员
			System.out.println(Outer.this.getName());	//访问外部类方法
		}
	}
}

1.1 编译Outer类会生成两个class文件:Outer.class和Outer$Inner.class。

1.2 非静态内部类中可以任意访问外部类的非静态成员和方法。

1.3 在非静态内部类中访问一个变量时,系统会优先在方法内部查找该变量,其次在内部类中,再在外部类中。如果内部类和外部类中存在相同名字的成员,则使用this.name代表内部类成员,使用Outer.this.name代表外部类成员。

1.4 外部类必须先显示创建内部类实例才能调用内部类的成员和方法。因为创建外部类实例并不代表着内部类实例也创建了。但是如果一个内部类实例创建了,那包裹它的外部类实例一定已经被创建了。

1.5 在非静态内部类中不能定义静态的成员,代码块和方法。如果非要定义,只能使用static final的。

1.6 根据静态成员不能访问非静态成员的规则,外部类中的静态成员不能访问非静态内部类的成员。除了非静态内部类中的static final成员。

1.7 在外部类以外的地方创建内部类实例的格式:外部类实例.new 内部类实例。前提是内部类的访问权限可以让外部类之外的环境访问。例如:

public class Temp {	
	public static void main (String args[]) {
		Outer.Inner inner = new Outer().new Inner();
		inner.printInfo();
	}
}

class Outer{
	private String name = "Outer class";
	public String getName() {
		return this.name;
	}
	public void print() {
		new Inner().printInfo();
	}
	public class Inner{
		private String name = "Inner class";
		public void printInfo(){
			System.out.println(this.name);	//访问本类成员
			System.out.println(Outer.this.name);	//访问外部类成员
			System.out.println(Outer.this.getName());	//访问外部类方法
		}
	}
}

1.8 子类继承非静态内部类:注意子类的构造方法中一定要有被继承的内部类的外部类的实例。

public class Temp {	
	public static void main (String args[]) {
		SubInner subInner = new SubInner(new Outer("外部类"));
		System.out.println(subInner.name);	//输出"子类",因为SubInner构造方法中调用的是Inner类的构造器,将"子类"字符串赋值到了Inner类中的name变量。
	}
}

class Outer{	//外部类
	public String name;
	public Outer(String name) {	//外部类构造方法
		this.name = name;
		System.out.println(this.name);	//输出"外部类",main方法中调用Outer类构造器的时候传入。
	}
	public class Inner{	//非静态内部类
		public String name;
		public Inner (String name) {	//非静态内部类构造方法
			this.name = name;
		}
	}
}

class SubInner extends Outer.Inner {
	public SubInner(Outer outer) {
		outer.super("子类");		//通过传入out的对象显示调用Inner类的构造器。注意:这里调的是Inner的构造器,不是Outer的。
	}
}


2. 静态内部类

public class Temp {	
	public static void main (String args[]) {
		Outer outer = new Outer();
		outer.print();
	}
}

class Outer{
	private static String name = "Outer class";
	public static String getName() {
		return name;
	}
	public void print() {
		System.out.println(Inner.name);
		new Inner().printInfo();
	}
	private static class Inner{
		private static String name = "Inner class";
		public void printInfo(){
			System.out.println(Inner.name);	//访问本类成员
			System.out.println(Outer.name);	//访问外部类成员
			System.out.println(Outer.getName());	//访问外部类方法
		}
	}
}
2.1 只有静态内部类中才可以包含静态成员。静态内部类中的静态成员不能访问外部类的非静态成员。

2.2 在外部类以外的地方创建静态内部类实例的格式:new 外部类类名.内部类实例。因为静态内部类是其外部类类相关的,因此创建静态内部类实例的时候不需要外部类的实例。

public class Temp {	
	public static void main (String args[]) {
		Outer.Inner inner = new Outer.Inner();
		inner.print();
	}
}

class Outer{
	private String name = "Outer class";
	public String getName() {
		return this.name;
	}
	public static class Inner{
		private String name = "Inner class";
		public void print() {
			System.out.println("内部类方法");
		}
	}
}

2.3 子类继承静态内部类:不需要外部类的实例。

public class Temp {	
	public static void main (String args[]) {
		SubInner subInner = new SubInner();
		System.out.println(subInner.name);	//输出"子类"。
	}
}

class Outer{	//外部类
	public String name;
	public Outer(String name) {	//外部类构造方法
		this.name = name;
		System.out.println(this.name);	//不会执行,因为实例化静态内部类的时候不需要调用外部类的构造器。
	}
	public static class Inner{	//静态内部类
		public String name;
		public Inner (String name) {	//静态内部类构造方法
			this.name = name;
		}
	}
}

class SubInner extends Outer.Inner {
	public SubInner() {
		super("子类");		//不需要传入out的对象。很显然,这里调的是Inner的构造器。
	}
}

3. 局部内部类:将内部类放在方法定义里。

public class Temp {   
    public static void main (String args[]) {  
        class Inner {	//局部内部类
        	int a = 1;
        }
        class SubInner extends Inner {	//第二个局部内部类,继承第一个局部内部类
        	int b = 2;
        }
        Inner inner = new Inner();	//创建局部内部类实例
        System.out.println(inner.a);
        SubInner subInner = new SubInner();
        System.out.println(subInner.a + " " + subInner.b);
    }  
}
3.1 因为局部内部类定义在方法内,因此局部内部类的适用范围仅在该方法里。根据所有局部成员都不存在访问控制符和static的原则:局部内部类不可能被外部类以外的地方使用,因此也无需使用访问控制符和static。

3.2 编译上面程序后会生成三个class文件:Temp.class,Temp$1Inner.class,Temp$1SubInner.class。注意到局部内部类的class文件名比内部类多了一个"1"。这是因为在一个类中不可能有重名的内部类,但是有可能有重名的局部内部类(在不同方法中定义)。这个数字便用于区分同名的局部内部类。


4. 匿名内部类:只是用一次的类。

4.1 匿名内部类创建后会立即生成该类实例,然后类定义消失。因此该类只能使用一次。定义匿名内部类的格式是:new 父类构造器 (参数列表|实现接口)。

4.2 匿名内部类必须且只能继承一个父类或实现一个接口。

4.3 匿名内部类不可能是抽象类,因为要生成类实例。

4.4 匿名内部类不能定义构造方法,但是可以有构造块。一般都是通过构造块完成构造方法的事情。

4.5 创建实现接口的匿名内部类的例子:

public class Temp {  
	public void testWork(Workable workable) {	//该方法需要传入一个实现Workable接口的实例
		System.out.println(workable.work());
	}
    public static void main (String args[]) {  
    	new Temp().testWork(new Workable() {	//定义匿名内部类,实现Workable接口
			public String work() {
				return ("工作");
    		}
    	});
    }
}  

interface Workable {	//定义一个接口,匿名内部类实现的便是这个接口
	public String work();
}
4.6 创建继承父类的匿名内部类的例子:

public class Temp {  
	public void testWork(Father father) {	//该方法需要传入一个继承Father类的实例
		System.out.println(father.work());
	}
    public static void main (String args[]) {  
    	new Temp().testWork(new Father("继承父类的匿名内部类") {	//继承父类的匿名内部类
    		public String work() {	//重写父类的work方法
    			return this.name + "在新地方工作";
    		}
    	});
    }
}  

class Father {	//定义一个父类
	public String name;
	public Father(String name) {	//定义父类的构造方法,需要传入一个String参数
		this.name = name;
	}
	public String work() {
		return this.name + "在工作";
	}
}

4.7 匿名内部类访问类外部的局部变量,该局部变量必须是final的,否则不能访问。

public class Temp {  
	public void testWork(Father father) {	//该方法需要传入一个继承Father类的实例
		System.out.println(father.work());
	}
    public static void main (String args[]) {  
    	final String newName = "类外部的局部变量";	//必须定义成final的
    	new Temp().testWork(new Father() {	//继承父类的匿名内部类
    		public String work() {	//重写父类的work方法
    			return newName + "在工作";	//newName必须是final的,否则编译报错
    		}
    	});
    }
}  

class Father {	//定义一个父类
	public String name = "父类";
	public String work() {
		return this.name + "在工作";
	}
}


你可能感兴趣的:(Java_内部类)