内部类:可以将一个类的定义放在另一个类的定义内部。
一、成员内部类
作为外部类的成员存在,与成员变量和成员方法平级关系。
1.1 声明
public class Out{
//成员变量
//成员方法
//成员内部类
访问权限 class In{
//成员变量
//成员方法
}
}
1.2 说明
1.2.1 语法说明
访问权限是任意的,内部类是属于外围类,就是为了更好控制,所以一般不用public.
1.2.2 如何创建成员内部类的对象
由于成员内部类作为外部类的成员存在,若想访问类成员需要通过对象,所以成员内部类对象需要通过外部类对象创建。
语法:
//创建外部类对象
Out o = new Out();
//通过外部类找到内部类,通过外部类对象创建内部类对象
Out.In i = o.new In();
1.2.3 如何在成员内部类中访问外部类的成员
i.当外部类的属性和内部类属性不同名时,可以直接访问
ii.当外部类属性与内部类属性同名时,格式:
外部类名.this.属性名(通过这个格式在内部类中访问外部类的同名属性)
1.2.4 成员内部类编译后字节码保存的文件格式
外围类:Outer.class 成员内部类:Outer$Inner.class
1.3 简单实现
public class Outer {
public int num = 10;//成员变量
//成员方法
void show1() {
System.out.println("成员方法show"+num);
}
//成员内部类 访问权限任意
class Inner {
public int num = 20;//成员内部类的成员变量
//成员内部类的成员方法
public void show() {
int num = 30;
System.out.println(num);
System.out.println(Inner.this.num);
//当内部方法中类访问外部类成员变量时 外围类.this.变量名
System.out.println(Outer.this.num);
}
}
public static void main(String[] args) {
//内部类作为外围类的成员变量存在,成员内部类的对象需要外围类对象创建
Outer outer = new Outer();
outer.show1();
Outer.Inner inner = outer.new Inner();
inner.show();
}
}
二、局部内部类
作为局部成员存在,和局部变量平级。
2.1 声明
public class Outer{
//成员变量
//成员方法
//局部内部类所在的方法
public void show(){
//功能代码
//局部内部类
访问权限 class Inner{
//局部内部类的成员变量
//局部内部类的成员方法
}
}
}
2.2 说明
局部内部类的访问权限:只能是默认
2.2.1 如何创建局部内部类对象
直接在局部内部类所在的方法中创建对象并调用方法
2.2.2 如何在局部内部类中访问外部类的属性:
i.不同名,直接访问
ii.同名,外部类名.this.属性名
2.2.3 字节码文件:
外部类名$编号内部类名.class

2.3 简单实现
public class Outer {
int num = 10;// 成员变量
// 成员方法
void show1() {
class In { } // 成员方法中定义一个类,局部内部类
System.out.println("外围类成员方法show" + num);
}
//局部内部类所在的方法
public void show() {
//public class In{}
class In{} //局部内部类只能是默认权限
class Inner {
int num = 30;
void display() {
int num =20;
System.out.println(num);
System.out.println(Inner.this.num);
System.out.println(Outer.this.num);
System.out.println("局部内部类的display方法");
}
}
//直接在局部内部类所在的方法中创建对象并调用方法
Inner i= new Inner();
i.display();
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.show1();
//局部内部类具有作用域,所以调用外部类对象的fun3方法时
//会声明局部内部类并创建对象调用方法
outer.show();
}
}
三、静态内部类
static修饰的外围类的成员内部类,只能是成员内部类。
3.1 声明
public class Out{
访问权限 static class In{
}
}
3.2 说明
访问权限:任意的,一般使用public
使用static修饰的成员内部类,自动提升为普通类,相当于一个独立的类,所有创建对象时不需要外围内对象。
3.2.1 创建对象:
不需要外部类的对象,可以直接创建静态内部类的对象
格式:内部类 标识符 = new 内部类构造方法
3.2.2 访问外部类的成员
只能直接访问外部类的静态成员
非静态的成员只能通过创建外部类对象访问
3.2.3 字节码文件格式:
外部类名$内部类名.class(与成员内部类一样)
Outer$Inner.class
3.3 简单实现
//static可以修饰类成员(属性,方法,块,成员内部类)
public class Outer {
public int num = 10;//成员变量
//成员方法
void show() {
System.out.println("外围类成员方法show"+num);
}
//静态内部类 访问权限任意,一般使用public
//使用static修饰的成员内部类,自动提升为普通类,相当于一个独立的类
public static class Inner {
public int num = 20;//静态内部类的成员变量
static String name ="Tom";
//静态内部类的成员方法
public void show() {
int num = 30;
System.out.println(num);
System.out.println(Inner.this.num);
//静态内部类里不能直接方法外围类非静态成员
//System.out.println(Outer.this.num);
//非静态的成员只能通过创建外部类对象访问
Outer o = new Outer();
System.out.println(o.num);
//只能直接访问外部类的静态成员
System.out.println(name);
System.out.println("static内部类的show方法");
}
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.show();
//不需要外部类的对象,可以直接创建静态内部类的对象
Inner inner = new Inner();
inner.show();
}
}
四、匿名内部类
4.1 说明
什么是匿名内部类: 没有名字的内部类
原理产生原因:
由于接口和抽象类不能创建对象,若一个接口的实现类只需要使用一次,或一个抽象类的非抽象类只需要使用一次,可以使用匿名内部类,匿名内部类只能创建一个对象
4.2 简单实现
public interface InterF {
void show();
}
public class Outer {
public static void main(String[] args) {
new InterF() {
@Override //重写抽象方法
public void show() {
System.out.println("重写匿名内部类show方法");
}
//匿名内部类中可以声明独有的属性和方法,但是由于接口引用不能
//访问实现类中独有的属性和方法,所以一般不在匿名内部类中声明独有的方法
public void display() {
System.out.println("独有的方法");
}
}.show();;
}
}
4.3匿名类编译后字节码文件格式
InterF.class
Outer$1.class
Outer.class
测试类$编号.class
匿名内部类只能使用一次,即便两次声明的匿名内部类完全一致,也是两个匿名内部类
4.4 匿名类的注意事项
匿名内部类中必须把抽象方法全部实现
匿名内部类中可以声明独有的属性和方法,但是由于接口引用不能访问实现类中独有的属性和方法,所以一般不在匿名内部类中声明独有的方法
匿名对象:若在匿名内部类中声明了独有的方法和属性,可以使用匿名对象访问,匿名对象只能使用一次
五、内部类的好处
每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类是没有影响的。
如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方法得以变得完整。接口解决了部分问题,内部类有效的实现了“多重继承”,也就是说内部类允许继承多个类或抽象类。
考虑以下的一种情况:在一个类中实现两个接口。一是用单一类,而是用内部类。
public interface A {
void show();
}
public interface B {
void fun();
}
//单一类实现A,B两个接口
public class ABImp implements A ,B{
public void show() {
System.out.println("show()--A");
}
public void fun() {
System.out.println("fun()--B");
}
}
//使用内部类
public class BInner implements A {
public void show() {
System.out.println("BInner_show");
}
B makeB() {
return new B() {
@Override
public void fun() {
System.out.println("BInner_fun");
}};
}
}
//测试类
public class Test {
public static void main(String[] args) {
ABImp abImp = new ABImp();
abImp.show();
abImp.fun();
BInner bInner = new BInner();
bInner.show();
bInner.makeB().fun();
}
}
以上两种方式从实现的较大看没有什么区别。但是这两种方式都有一定的逻辑意义,当遇到问题的时候通常问题本身就会给出某些指引,告诉你应该怎样使用。
上面面向的是接口,那如果拥有的是类或者抽象类,那就只能使用内部类实现多重继承。
//普通具体类
public class D {
void run() {
System.out.println("D-run");
}
}
//抽象类
public abstract class E {
abstract void play() ;
}
//内部类实现多重继承
public class Z extends E {
void play() {
System.out.println("Z_E_play");
}
D makeD() {
return new D() {};
}
}
内部类的特性:
1、内部类是一种非常有用的特性,它允许你把一些逻辑相关的类组织在一起,并控制位于内部的类的可视性。看起来就像是一种代码隐藏机制:将类置于其他类的内部。
2、内部类可以拥有多个实例,每个实例都有自己的状态信息,并且与其外围类对象的信息相互独立。
3、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口或继承同一个类。
4、内部类没有“is-a”关系,它是独立的实体。
5、静态内部类(嵌套类)不需要对外围类对象的依赖即可创建对象,还可以定义static变量或方法。但是局部、成员、匿名内部类不能定义静态的成员,成员内部类对象的创建需要依赖外围类对象的引用。