一、基本介绍
内部类是指在一个外部类的内部再定义一个类。类名不需要和文件夹相同。
内部类可以是静态static的,也可用public,default,protected和private修饰;而外部顶级类即类名和文件名相同的只能使用public和default。
注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。对于一个名为Outer的外部类和其内部定义的名为Inner的内部类。编译完成后出现Outer.class和Outer$Inner.class两类。
二、分类
1、静态内部类
类定义时加上static关键字。
只可以访问外部类的静态成员和静态方法,包括了私有的静态成员和方法。
被编译成一个完全独立的.class文件,名称为OuterClass$InnerClass.class的形式。
生成静态内部类对象的方式为:
OuterClass.InnerClass inner = new OuterClass.InnerClass();
public class Outer { public static String sayStr=" say hello"; public static void main(String[] args){ Outer.StaticInner inner=new StaticInner(); inner.say(); } public static class StaticInner{ public void say(){ //静态内部类只能访问外部内的静态成员和静态方法 System.out.println(sayStr); } } }
2、成员内部类
成员内部类也是定义在另一个类中,但是定义时不用static修饰。
成员内部类和静态内部类可以类比为非静态的成员变量和静态的成员变量。
被编译成一个完全独立的.class文件,名称为OuterClass$InnerClass.class的形式。
它可以访问它的外部类的所有成员变量和方法,不管是静态的还是非静态的都可以。
在外部类里面创建成员内部类的实例:
this.new Innerclass();
在外部类之外创建内部类的实例:
(new Outerclass()).new Innerclass();
在内部类里访问外部类的成员:
Outerclass.this.member
public class Test { public static void main(String[] args) { // 创建内部类对象时需要先创建外部对象 Outer.Inner inner=new Outer().new Inner(); inner.say(); } } class Outer{ private String sayStr="hello"; public class Inner{ public void say(){ System.out.println(Outer.this.sayStr); } } }
3、局部内部类
局部内部类定义在方法中,比方法的范围还小。是内部类中最少用到的一种类型。
像局部变量一样,不能被public, protected, private和static修饰。
只能访问方法中定义的final类型的局部变量。
局部内部类在方法中定义,所以只能在方法中使用,即只能在方法当中生成局部内部类的实例并且调用其方法。
被编译成一个完全独立的.class文件,名称为OuterClass$数字InnerClass.class的形式。 如果不同方法中局部内部内类名相同,被编译成class文件时用数字区分
public class LocalInnerTest { public static void main(String[] args){ Outer outer=new Outer(); outer.doSomething(); } } class Outer{ int a=1; public void doSomething(){ int b=2; final int c=3; class Inner{ int d=4; public void work(){ //可以访问外部内的成员变量 System.out.println(a); //不可以访问非final的局部变量 //System.out.println(b); //可以访问final的局部变量 System.out.println(c); //可以访问内部类自身所有变量 System.out.println(d); } } //创建局部内部类的实例并调用方法 new Inner().work(); } }
4、匿名内部类
匿名内部类就是没有名字的局部内部类,不使用关键字class, extends, implements, 没有构造方法。
匿名内部类隐式地继承了一个父类或者实现了一个接口。
匿名内部类使用得比较多,通常是作为一个方法参数。
生成的.class文件中,匿名类会生成OuterClass$数字.class文件,数字根据是第几个匿名类而类推。
匿名内部类不能定义任何静态成员、方法和类。
匿名内部类不能是public,protected,private,static。
案例一:
import java.util.Date; public class AnonymouseInnerClass { public String getStr(Date date){ return date.toLocaleString(); } public static void main(String[] args){ AnonymouseInnerClass anon=new AnonymouseInnerClass(); String str=anon.getStr(new Date()); System.out.println(str); //使用匿名内部类 str=anon.getStr(new Date(){ //使用了花括号,但是不填入内容,执行结果和上面的完全一致 //生成了一个继承了Date类的子类的对象 }); System.out.println(str); //使用匿名内部类,并且重写父类中的方法 str=anon.getStr(new Date(){ //重写父类中的方法 @Override public String toLocaleString(){ return "hello "+super.toLocaleString(); } }); System.out.println(str); } }
案例二:
public class Anonymouse { public static void main(String[] args){ Outer outer=new Outer(){ //重写show方法 @Override public void show(){ System.out.println("Anonymouse:show"); } }; outer.show(); } } class Outer{ public void show(){ System.out.println("Outer:show"); } }
案例三:
public class Anonymouse { public static void main(String[] args){ Anonymouse anon=new Anonymouse(); anon.print(new Bird(){ @Override public int fly() { return 1000; } public String getName(){ return "大雁"; } }); } public void print(Bird bird){ System.out.println(bird.getName()+"能飞"+bird.fly()+"米"); } } abstract class Bird{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public abstract int fly(); }
案例四:
public class Anonymouse { public static void main(String[] args){ //通过匿名内部类,实现eat方法 Bird bird=new Bird() { @Override public void eat() { System.out.print("Anonymouse:eat"); } }; //调用eat方法 bird.eat(); } } abstract class Bird{ public abstract void eat(); }
案例五:
public class Anonymouse { public static void main(String[] args){ //通过匿名内部类,实现eat方法 IBird bird=new IBird() { @Override public void eat() { System.out.print("Anonymouse:eat"); } }; //调用eat方法 bird.eat(); } } interface IBird{ public void eat(); }