目录
1.内部类概述
1.1 什么是内部类?
1.1.1 内部类顾名思义,将类置于其他类的内部(接口内部也可以,具体看静态内部类部分详解);
1.2 为什么需要内部类?(可以后看)
1.2.1 内部类提供了某种进入其外部类的窗口;
1.2.2 每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响;这句话是最精辟的
1.2.3 Java不支持类的多重继承,但是提供接口间接以实现Java的多重继承功能,而内部类的出现使多重继承变得更加完整;
1.2.4 在单个外部类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类;
1.2.5 对于静态内部类,内部类的对象创建并不依赖于外部类对象;
1.2.4 举个栗子,比如波音飞机继承了飞机类,但是波音飞机还想继承交通工具类的属性功能,不存在接口的情况下,只能通过使用内部类实现多重继承:
1)交通工具类
package org.ssm.java.innerClass;
/*
* 交通工具类
* */
public class Vehicle {
/*
* 方法:载客
* */
void carry(){
System.out.println("载客功能。。。");
}
}
2)飞机类
package org.ssm.java.innerClass;
/*
* 飞机
* */
public class Plane {
private String name;
private String type;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
3)波音飞机类
package org.ssm.java.innerClass;
import com.hp.hpl.sparta.xpath.ThisNodeTest;
/*
* 波音飞机
* */
public class Boeing extends Plane {
private String num;
private void descript(){
System.out.println("我是波音飞机");
}
class Inner extends Vehicle{
Vehicle getVehicle(){
return new Vehicle();
}
}
private Vehicle getInner(){
return new Inner();
}
public static void main(String[] args) {
Boeing boeing = new Boeing();
Boeing.Inner inner = (Inner) boeing.getInner();
inner.carry();
Vehicle vehicle = inner.getVehicle();
vehicle.carry();
}
}
2.成员内部类
package org.ssm.java.innerClass.member;
/*成员内部类*/
public class Outer {
/*成员属性*/
public int num;
/*私有属性*/
private String name;
/*静态成员*/
private final static String TYPE = "Outer";
/*带参构造器*/
public Outer(int num, String name) {
super();
this.num = num;
this.name = name;
}
/*成员方法*/
private void descript(){
System.out.println("I am "+name);
}
/*静态方法*/
private static boolean isOuter(){
return true;
}
/*内部类*/
class Inner{
public int innnerNum = 0;
/*内部类属性、构造器和方法*/
private String name;
public Inner(String name) {
this.name = name;
}
/*内部类成员方法*/
private void descript(){
System.out.println("I am "+name);
}
/*访问外部类成员:包括静态和成员属性*/
private void getOuterAttribute(){
System.out.println("-----------------------");
System.out.println("我访问外部类的成员属性num:"+num);
System.out.println("我访问外部类的静态属性Type:"+TYPE);
System.out.println("我访问外部类的成员方法:");
Outer.this.descript();
System.out.println("我访问外部类的静态方法:"+Outer.this.isOuter());
}
}
/*提供创建内部类对象的方法*/
private Inner getInner(String name){
return new Inner(name);
}
public static void main(String[] args) {
/*创建外部类对象*/
Outer outer = new Outer(888, "outer");
/*创建内部类对象*/
Outer.Inner inner = outer.new Inner("inner");
//Outer.Inner inner2 = outer.getInner("inner");
inner.descript();
/*内部类对象访问外部类成员*/
inner.getOuterAttribute();
}
}
/*控制台输出:
I am inner
-----------------------
我访问外部类的成员属性num:888
我访问外部类的静态属性Type:Outer
我访问外部类的成员方法:
I am outer
我访问外部类的静态方法:true*/
1.1 成员内部类作为外部类的一个成员存在,与外部类的属性、方法并列;
1.2 外部类的非静态方法之外的任意位置创建某个内部类对象,必须具体的指明这个对象的类型:OuterClassName.InnerClassName;创建内部类对象必须使用外部类对象来创建,可以使用new,也可以在外部类中提供返回内部类对象的方法;
/*创建内部类对象*/
Outer.Inner inner = outer.new Inner("inner");
//Outer.Inner inner2 = outer.getInner("inner");
1.3 内部类和外部类之间还存在通信,当生成一个内部类的对象时,此对象与它的外部类对象之间还存在联系,内部类对象能访问外围对象的所有成员,而不需要任何特殊条件,内部类拥有其外部类的所有元素的访问权;这个是怎么做到的呢?当某个外部类对象创建内部类对象时,此内部类对象必定会秘密捕获一个指向那个外围类对象的引用,然后,在你访问外部类成员时,就是用那个引用来选择外部类的成员;
1.4 内部类访问外部类的实例变量:外部类名.this.属性,如上Outer.this.num;
1.5 成员内部类不能定义静态成员,只能定义对象成员;但是静态内部类可以;
1.6 上述说到创建内部类对象之前外部类对象必须先创建,是因为内部类对象会暗暗地连接到创建他的内部类对象上,但是我们不想内部类对象和外部类对象扯上联系怎么办呢?那就需要静态内部类了;静态内部类又是什么妖魔鬼怪呢?下面来了解一下:
2.静态内部类
2.1 在内部类声明为static即为静态内部类,也叫嵌套类;
package org.ssm.java.innerClass.staticInner;
import aj.org.objectweb.asm.Type;
/*静态内部类*/
public class Outer {
private String name;
private static String TYPE = "Outer";
public Outer(String name) {
this.name = name;
}
private static void descript(){
System.out.println("I am "+TYPE);
}
private static class Inner{
/*静态属性*/
public static String TYPE ="Inner";
private String name;
public Inner(String name) {
this.name = name;
}
/*内部类成员方法*/
private void descript(){
System.out.println("I am "+name);
}
/*访问外部类成员:包括静态和成员属性*/
private void getOuterAttribute(){
System.out.println("-----------------------");
System.out.println("我访问外部类的静态属性Type:"+TYPE);
System.out.println("我访问外部类的静态方法:");
Outer.descript();
}
}
private Inner getInner(String name){
return new Inner(name);
}
public static void main(String[] args) {
Inner inner = new Inner("Inner");
inner.descript();
Outer.Inner inner2 = new Outer("Outer").getInner("Inner2");
inner2.descript();
inner2.getOuterAttribute();
/* 输出:
I am Inner
I am Inner2
-----------------------
我访问外部类的静态属性Type:Inner
我访问外部类的静态方法:
I am Outer
*/
}
}
2.2 既然内部类被声明为static,那要创建内部类对象就不需要创建外部类对象,与此同时静态内部类的对象也不能访问外部类对象的非静态成员和方法;因为类的非静态成员的访问必须依赖于类的实例对象;
2.3 在介绍成员内部类时介绍到,成员内部类不能定义静态成员,但是静态内部类可以;
2.4 在成员内部类里,可以通过外部类名.this链接到外部类对象,但是静态内部类就没有this;
2.5 静态内部类可以定义在接口内部,特殊的是放置在接口中的内部类都自动是public和static的,这是接口的规则;
3.局部内部类
3.1 在一个方法里或者在任意的作用域内定义内部类;
package org.ssm.java.innerClass.partInner;
public class Outer {
private String name ;
private PartInterface partInterface(){
class Inner implements PartInterface{
private String name;
@Override
public void descript() {
System.out.println("局域内部类描述");
}
}
return new Inner();
}
public static void main(String[] args) {
Outer outer = new Outer();
PartInterface partInterface = outer.partInterface();
partInterface.descript();
}
}
3.2 局部内部类访问作用域内的局部变量,该局部变量需要使用final修饰;
4.匿名内部类
4.1 先举个栗子了解一下:
package org.ssm.java.innerClass.anonymous;
public class SuperInner {
private void descript(){
System.out.println("内部类的父类");
}
}
package org.ssm.java.innerClass.anonymous;
public interface SuperInterface {
void descript();
}
package org.ssm.java.innerClass.anonymous;
/*
* 匿名内部类
* */
public class Outer {
/*
* 继承父类
* */
public SuperInner superInner(){
return new SuperInner(){
private String name;
public void descript(){
System.out.println("我是内部类1号");
}
public void content() {
System.out.println("333332");
}
};
}
/*
* 实现接口
* */
public SuperInterface superInterface() {
return new SuperInterface() {
@Override
public void descript() {
System.out.println("我是内部类2号");
}
};
}
public static void main(String[] args) {
Outer outer = new Outer();
SuperInner superInner = outer.superInner();
superInner.descript();
superInner.content();
SuperInterface superInterface = outer.superInterface();
superInterface.descript();
/*
* 输出:
我是内部类1号
333332
我是内部类2号*/
}
}
4.2 注意上述代码中Outer类中的方法superInner(),是不是感觉很突兀,这种奇怪的代码意思大概是:创建一个继承自SuperInnner的匿名类的对象,换句话说就是这个方法返回一个对象,这个对象的类是方法返回类型SuperInnner的子类,这个子类没有名字定义,方法返回子类的对象,然后通过向上转型将子类对象的引用转型为父类SuperInnner的引用;
4.3 下面是匿名类定义的格式:
匿名内部类定义和实例化形式如下:
new 父类构造方法(参数){
//注:该方法名必须在父类中已经存在
修饰符 返回参数类型 方法名(参数列表){
。。。
}
}
4.3 观察上述提供的匿名内部类格式,匿名内部类必须继承于一个类,抽象的也可以,或者实现一个接口,二选其一,不能兼备,不能多继承接口;
4.3.1 如果是继承于抽象类,匿名内部类中必须实现父类所有的方法;
4.3.2 如果是实现接口,内部类必须重写接口中所有的方法;
4.4 匿名内部类不能是抽象类,所以不能包含抽象方法,因为方法会返回一个实例,抽象类无法创建实例;
4.5 既然是匿名内部类,所以它也没有构造器,因为内部类没有名字,与构造器规则不符;
4.6 可以定义新的方法和属性(不能使用static修饰),但是无法显式的通过“实例名.方法名(参数)”的形式调用,因为使用new创建的是“上转型对象”(即父类声明指向子类对象),如果想调用,只能在父类定义同样的方法和属性;
5.内部类标识符
5.1 我们都知道,每个类都会产生一个.class文件,内部类也会产生一个.class文件,内部类的命名规则为:外部类名字$内部类名字.class,所以不要问同事某个文件名字怎么这么起,显得自己业余;
分享一个博客,里面做的表格比对各类内部类很好,值得推荐:https://www.cnblogs.com/dorothychai/p/6007709.html