天天看点

Java内部类浅谈

什么是内部类

把一个类放在另一个类的内部叫做内部类。

内部类的作用

①提供了更好的封装,把内部类隐藏在外部类之内部不允许其他类访问。比如说定义一个类为牛,它的一个内部类是牛腿。牛腿类不能够让其他的类访问,也就是一旦牛腿类离开牛的话就会毫无意义。

②适合于创建那些需要一次性使用的类。比如说在添加事件响应的类中。

内部类对象的核心

用内部类创建的对象叫做内部类对象,内部类中能够调用外部类中的一些方法与属性究其原因是:内部类对象中含有外部类对象的引用!(这个知识点本来没什么但是我觉得很激动人心)

Java内部类浅谈

正是由于这个道理我们就能够更加简单的认识到静态内部类与非静态内部类的区别。

在一般情况下非静态的对象能够访问静态的(static)属性与方法但是反过来就不行。静态的对象只能访问静态相关的属性与方法。将这个规则放到内部类中我们就能解释为什么非静态内部类能够访问外部类中的静态的属性与方法而静态内部类不能够访问外部类中的非静态的属性与方法了。原因就是:非静态内部类中含有外部类对象的引用,而静态内部类不含有外部类对象的引用。

上代码:

非静态内部类的调用相关

package innerClassStatic;

public class NonStatic {
	
	private String str = "非静态字符串";
	private static String str1 = "静态字符串";
	class Inner{
		
		public void test() {
			System.out.println(str);
			System.out.println(str1);
			test1();
			test2();
		}
		
	}
	
	public void test1() {
		
	}
	
	public static void test2() {

	}
	
	public void startTest() {
		new Inner().test();
	}
	
	public static void main(String[] args) {
		new NonStatic().startTest();
	}
	
}
           

静态内部类的调用相关

package innerClassStatic;

public class Static {
	
	private String str = "非静态字符串";
	private static String str1 = "静态字符串";
	static class Inner{
		
		public void test() {
			//System.out.println(str);//静态的内部类方法不能访问非静态内部类方法
			System.out.println(str1);
			test2();  
		}
		
	}
	
	public void test1() {
		
	}
	
	public static void test2() {
		
	}
	
	public void startTest() {
		/*new Inner().test1();
		new Inner().test2();*///任何的内部类对象都不能调用外部的方法
		new Inner().test();
	}
	
	public static void main(String[] args) {
		new Static().startTest();
	}
	
}
           

内部类中关于变量的访问(非静态)

这个比较简单直接上代码:

package innerClassthis;

public class DV {
	private String prop = "外部类的实例变量";
	public class Inner{
		private String prop = "内部类的实例变量";
		private void info() {
			String prop = "局部变量";
			System.out.println("DV.this.prop  "+DV.this.prop);//外部类变量
			System.out.println("this.prop  "+this.prop);//内部类变量
			System.out.println("prop"+prop);//局部变量
		}
	}
	
	public void test() {
		Inner in = new Inner();
		in.info();
	}
	
	public static void main(String[] args) {
		new DV().test();
	}
}
           

在外部类之外创建非静态内部类

这里不说静态内部类就是因为静态内部类隶属于外部类当使用静态内部类的时候直接是:外部类.静态内部类.方法;

但是非静态内部类对象属于内部类,它寄生于外部类对象。没有寄主是没有寄生物的。所以在外部类之外创建内部类对象的时候需要先创建外部类对象:

package innerUse;

class Out{
	class In{
		public In(String msg) {
			System.out.println(msg);
		}
	}
}

public class InnerUse{
	public static void main(String[] args) {
		Out.In in = new Out().new In("test msg");//由于寄生的关系所以先创建一个外部类然后才能创建内部类
        //底下的效果同上
		Out.In inner;
		Out out = new Out();
		inner = out.new In("test msg1");
	}
}
           

匿名内部类

匿名内部类在功能上是一种只使用一次的类。创建匿名内部类时会立即创建该类的一个实例之后会立即消失。匿名内部类不能重复使用。

这就诞生了它的两个特点:

①匿名内部类不能是抽象类,抽象类不能实例化而创建匿名内部类时会立即创建该类的一个实例。

②匿名内部类不能定义构造器,因为匿名内部类没有类名。它的初始化工作可以通过初始化块来完成。

另外匿名内部类必须只实现一个借口或继承一个父类。

两个例子:

匿名内部类实现一个接口,此时匿名内部类只有一个隐式的构造器。

package AnonymousInnerClass;

interface Product{
	double getPrice();
	String getName();
}

public class AnonymousTest {
	public void test(Product p) {
		System.out.println("买了一本"+p.getName()+","+"花了"+p.getPrice());
	}
	
	public static void main(String[] args) {
		AnonymousTest at = new AnonymousTest();
		at.test(new Product() {//实现接口的无参数
			@Override
			public double getPrice() {
				return 100.0;
			}
			@Override
			public String getName() {
				return "见识";
			}
		});
		
	}
}
           

匿名内部类继承抽象类

package AnonymousInnerClass;

abstract class Device{
	private String name;

	public abstract double getPrice();
	public Device() {}
	public Device(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
}

public class AnonymousInner2 {
	public void test(Device dev) {
		System.out.println("买了一个"+dev.getName()+"花了"+dev.getPrice());
	}
	public static void main(String[] args) {
		AnonymousInner2 a2 = new AnonymousInner2();
		a2.test(new Device("华硕") {
			@Override
			public double getPrice() {
				return 9999;
			}
		});
		
		a2.test(new Device() {
			{
				System.out.println("这是一个初始化块!");
			}
			@Override
			public double getPrice() {
				return 9998;
			}
			
			public String getName() {
				return "DELL";
			}
		});
	}
}
           

Java8新增effective final

在Java8之前被匿名内部类与局部内部类访问的局部变量必须是final修饰的。但是在Java8之后取消了这一规定局部变量不在必须由final来修饰但是所有在使用的局部变量都有一个隐式的final在修饰。