Java之有名内部类与匿名内部类

有名内部类

接口:

public interface Mammal {

	public abstract void move();
}

有名内部类:

public class Body {

	//有名内部类
	class Heart{
		public void work() {//有名内部类的方法
			System.out.println("正在跳动......");
		}
	}
	//静态代码块,创建对象时执行
	{
		Heart heart = new Heart();
		heart.work();
		//在非静态代码块中默认在new前有个 “this.”,故不用再加 “body.”
	}
	
	public static void main(String[] args) {
		Body body = new Body();//创建对象
		Heart heart = body.new Heart();//创建有名内部类对象,需要加 “主类的对象.”
		heart.work();//通过有名内部类对象调用其work方法
	}
}

结果:

正在跳动......
正在跳动......

匿名内部类

匿名内部类:必须和创建对象一起存在

创建方法:
 new 父类构造器([参数列表])|接口(){
   匿名内部类类体;
 }

注:匿名内部类创建的对象一定是普通类或抽象类的子类对象,或接口的实现类

接口:

public interface Mammal {

	public void move();
}

匿名接口内部类:

public class Body {
	
	//匿名内部类由于没有名字,所以定义匿名内部类的同时要创建对象
	int age = 2;//就如同这一样,必须把2赋值给一个变量,而不能单独写一个2
	static Mammal mammal = new Mammal() {//匿名内部类,Mammal接口的实现类,static是为了能在下面主函数中直接调用这个内部类
		@Override
		public void move() {//重写接口的抽象方法
			System.out.println("靠鳍游动......");
		}
		
		public void eat() {//新定义的方法
			System.out.println("正在吃......");
		}
	};
	
	public static void main(String[] args) {
		mammal.move();//调用匿名内部类的move方法
		
		/*匿名内部类常用于重写父类或者接口中的方法,当然也可以定义新的属性和方法,但此方法上转型对象无法调用
		例如:
		mammal.eat();不能这样直接用上转型对象mammal调用eat方法*/
		
		//可以通过下面方式来调用eat方法,但此时重写的move方法就无效了,没有必要这样用
		new Mammal() {//匿名内部类
			@Override
			public void move() {
				System.out.println("靠鳍游动......");
			}
			
			public void eat() {
				System.out.println("正在吃......");
			}
		}.eat();//直接调用eat方法
	}
}

结果:

靠鳍游动......
正在吃......

匿名普通的内部类:

public class Test2 {

	//匿名内部类由于没有名字,所以定义匿名内部类的同时要创建对象
	int age = 2;//就如同这一样,必须把2赋值给一个变量,而不能单独写一个2
	Object object = new Object() {//以Object为父类创建内部类
		public void move() {
			System.out.println("......");
		}
	};

	public static void main(String[] args) {
		//非上转型对象可以调用子类新增的属性和方法,但此时没有必要这么麻烦,且只能调用一个
		new Object() {
			public void move() {
				System.out.println("......");
			}
		}.move();
	}
}

匿名内部类对象:匿名内部类是普通类的子类;是接口的实现类
类体通常用于实现抽象方法或重写父类方法,但也可以丁意思自己新增的属性和变量
Object为父类,new Object()为子类,则object为上转型对象
匿名内部类中新增的属性和方法,无法在上转型对象中使用

内部类中使用外部变量

public class Test3 {

	public void test(){
		int age = 12;//局部变量
		class Printer{
			public void print(){
				System.out.println(age);//在内部类中使用了内部类外的变量
			}
		}//内部类
	}
}

内部类中可以直接使用外部变量(内部类必须在外部变量作用范围内)
如果内部类中使用了局部变量,则JDK8以前的版本中必须在局部变量前加final修饰

特殊的匿名内部类:函数式接口

函数式接口:
仅有一个抽象方法的接口可以使用@FunctionalInterface注解修饰,这样的接口称之为函数式接口。

接口:

@FunctionalInterface
public interface IComputer {//函数式接口

	int add(int a,int b);
}

由该接口创建内部类:

public class Test4 {

	public static void main(String[] args) {
		//按常规方法创建匿名内部类
		IComputer computer = new IComputer() {
			@Override
			public int add(int a,int b) {
				return a+b;
			}
		};
		
		//Lambda方法创建:主要用于简化匿名内部类(JDK8以及以上)
		IComputer computer =(int a,int b)->{
			return a+b;
		};
		
		//也可以忽略不写参数的数据类型
		IComputer computer =(a,b)->{
			return a+b;
		};
		
		
		//如果方法体仅仅是一行返回值,则大括号和return可省略(同时省略)
		IComputer computer =(a,b)-> a+b;
		
		//输出结果
		int result = computer.add(1, 1);
		System.out.println(result);
	}
}

内部类的访问权限

1、外部类或者外部接口的访问权限必须是public或者默认的
2、内部类或者内部接口则四种访问权限都可以
3、局部内部类不允许添加任何访问控制符

public class Test {//外部类必须是public或者默认的

	//内部类访问权限定义方法像成员变量一样直接定义在内部类前
	private int age;
	private class Herat{
		
	}
	
	public static void main(String[] args) {
		//局部内部类的定义和局部变量一样,都不允许添加访问控制符
		int age;
		class Body{
			
		}
	}
}

内部类的class文件

普通类:

package venus;

public class Mammal {

}

内部类:

package venus;

public class Body {

	
	class A{//有名内部类
		
	}
	
	Mammal mammal = new Mammal() {//匿名内部类
		
	};
	
	Object object = new Object() {//匿名内部类
		
	};
	
	public static void main(String[] args) {
		
	}
	
}

则在eclipse-workspace\venus\bin文件夹中生成了class文件如下:
在这里插入图片描述
其中Mamma l.class和Body.class为两个类的class文件
Body$A.class为Body类中有名内部类的class文件
Body$1.class和Body$2.class为Body类中的匿名内部类的class文件

总结:
有名内部类编译后生成“外部类 $ 内部类 . class”文件
匿名内部类编译后生成“外部类 $ 数字 . class”文件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章