Java 内部类分析


前言

挺久之前整理的,才疏学浅,若有不足,还请指出

内部类概述

内部类是指在一个外部类的内部再定义一个类,类名不需要和文件夹相同。内部类可以声明 public 、protected 、private 等访问限制,可以声明为 abstract的供其他内部类或外部类继承与扩展,或者声明为static 、final 的,也可以实现特定的接口(而外部顶级类即类名和文件名相同的只能使用 public 和 default)。static 的内部类行为上象一个独立的类,非 static 在行为上类似类的属性或方法且禁止声明 static 的方法。内部类可以访问外部类的所有方法与属性,但 static 的内部类只能访问外部类的静态属性与方法

内部类优缺点:

  • 1)在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或继承同一个类

  • 2)内部类是另外一种封装,将存在一定逻辑关系的类组织在一起,对外界类隐藏

  • 3)内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立

  • 4)创建内部类对象的时刻并不依赖于外围类对象的创建

  • 5)内部类与外部类可以方便的访问彼此的私有域(包括私有方法、私有属性)

  • 6)内部类可以实现JAVA的单继承局限

  • #7)方便编写事件驱动程序,方便编写线程代码

基础使用内部类:

(1)创建内部类:
1)在外部类外部 创建非静态内部类
语法: 外部类.内部类 内部类对象 = new 外部类().new 内部类();
举例: Outer.Inner in = new Outer().new Inner();
2)在外部类外部 创建静态内部类
语法: 外部类.内部类 内部类对象 = new 外部类.内部类();
举例: Outer.Inner in = new Outer.Inner();
3) 在外部类内部创建内部类
语法:在外部类内部创建内部类,就像普通对象一样直接创建:Inner in = new Inner();

(2)访问内部类及内部类访问外部类

/**
 * 外部类、成员内部类的定义
 */
public class OutClass {

 /**
     * 私有全局变量
     */
 private int out_int = 1;
    private int out_int2 = 2;
    private int Classint = 100;
    /**
     * 私有静态全局变量
     */
    private static int out_Static_int = 3;

    /**
     * 成员方法
     */
    public void outerMethod() {
        System.out.println("外部类outerMethod方法");
    }

    /**
     * 静态方法
     */
    public static void outerStaticMethod() {
        System.out.println("外部类outerStaticMethod静态方法");
    }

    /**
     * 内部类
     */
    public class InClass {
    
        private int Classint = 10;

        /**
         * 构造方法
         */
        public InClass() {
        }

        /**
         * 成员方法,访问外部类信息(属性、方法)
         */
        public void inClassShow() {
            //当和外部类冲突时,直接引用属性名,是内部类的成员属性
            System.out.println("输出内部变量Classint:" + Classint);
            //内部类访问外部属性
            System.out.println("输出外部变量out_int:" + out_int);
            //当和外部类属性名重叠时,可通过外部类名.this.属性名
            System.out.println("输出外部变量Classint:" + OutClass.this.Classint);
            System.out.println("输出外部静态变量out_Static_int:" + out_Static_int);
            //访问外部类的方法
            outerMethod();
            //访问外部类的静态方法
            outerStaticMethod();
        }
    }
    
    /**
     *	外部类访问内部类信息
     */
    public void outerShow() {
    	InClass in = new InClass();
    	in.inClassShow();
    }
    public static void main(String args[])
    {
    	OutClass o = new OutClass();
    	o.outerShow();
    }
}

(3)其他类访问内部类:

public class Other {
    
    public static void main(String[] args) {
        //外部类对象
        OutClass outer = new OutClass();
        //创造内部类对象
        OutClass.InClass inner = outer.new InClass();
        //调用内部类方法
        inner.inClassShow();
    
    }
}

注意:
1)普通内部类的内部不能有静态变量和静态方法
2)成员内部类是依附外部类的,只有创建了外部类才能创建内部类

内部类的种类:

(1)成员内部类
————见上—————
(2)静态内部类

1)静态内部类概述:
关键字static可以修饰成员变量、方法、代码块、其实还可以修饰内部类,使用static修饰的内部类称之为静态内部类,
注:静态内部类和非静态内部类之间存在的区别:非静态内部类在编译完成之后会隐含的保存着一个引用,该引用是指向创建它的外围类,但是静态类没有引用,所以其具有以下特点:

  • 静态内部类的创建不需要依赖外部类可以直接创建
  • 静态内部类不可以使用任何外部类的非static类(包括属性和方法),但可以存在自己的成员变量

对于静态内部类我们可能在平时的编程环境中不多见,但是在某些项目中,很多都使用了静态内部类,这种场景一般针对于静态内部类不需要外部类的资源,而外部类需要使用内部类的时候

2)访问静态内部类

/**
 * 外部类、内部类定义
 */
class OutClass {

    private int out_int = 1;

    /**
     * 外部类定义的属性(重名)
     */
    private int Class_int = 2;
    
    private static int out_Static_int = 3;

    static {
        System.out.println("执行了外部类的静态代码块");
    }

    /**
     * 成员方法
     */
    public void outMothod() {
        System.out.println("外部类outMethod方法");
    }

    /**
     *	静态方法
     */
    public static void outStaticMethod() {
        System.out.println("外部类的outStaticMethod静态方法");
    }


    /**
     * 静态内部类
     */
    public static class InClass {
        /**
         * 成员信息
         */
        private int in_int = 10;
        private int Class_int = 20;

        static {
            System.out.println("执行了OutClass.InClass的静态块");
        }

        private static int in_Static_int = 30;

        /**
         * 成员方法
         */
        public void inClassShow() {
            System.out.println("输出静态内部类私有变量in_int:" + in_int);
            System.out.println("输出静态内部类同名私有变量Class_int:" + Class_int);
            //System.out.println("输外部类同名私有变量Class_int:" + OutClass.this.Class_int);
            //errror:静态类不能直接访问非静态方法,字段
            System.out.println("输出静态内部类静态变量in_Static_int:"+in_Static_int);
            System.out.println("输出外部类静态变量out_Static_int:"+out_Static_int);
            //调用外部类静态方法
            outStaticMethod();
        }

        /**
         * 静态方法
         */
        public static void innerStaticShow() {
        	//被调用时会先加载OutClass类
            outStaticMethod();
            System.out.println("输出外部类静态变量out_Static_int:"+out_Static_int);
        }
    }

    /**
     * 外部类如何访问内部类的方法及变量
     */
    public static void callInner() {
        System.out.println(InClass.in_Static_int);
        InClass.innerStaticShow();
    }
}
public class Other {

    public static void main(String[] args) {
        //访问静态内部类的静态方法,InClass类被加载,此时外部类OutClass未被加载,静态内部类独立存在,不依赖于外部类
        //静态的内部类的实例化可以直接通过外部类.的形式来进行
        OutClass.InClass.innerStaticShow();
        //访问静态内部类的成员方法
        OutClass.InClass in = new OutClass.InClass();
        in.inClassShow();
    }
}

控制台输出:

执行了OutClass.InClass的静态块
执行了外部类的静态代码块
//注意:读取或者设置一个类的静态字段以及调用一个类的静态方法的时候,会导致该类被初始化,初始化后会执行该类静态代码块
外部类的outStaticMethod静态方法
输出外部类静态变量out_Static_int:3
输出静态内部类私有变量in_int:10
输出静态内部类同名私有变量Class_int:20
输出静态内部类静态变量in_Static_int:30

注意:当main方法中只包含以下语句时:

OutClass.InClass in = new OutClass.InClass();
        in.inClassShow();

控制台输出内容如下:

执行了OutClass.InClass的静态块
输出静态内部类私有变量in_int:10
输出静态内部类同名私有变量Class_int:20
输出静态内部类静态变量in_Static_int:30
执行了外部类的静态代码块
//到需要输出外部静态变量时,外部类初始化,并执行该类的静态代码块
输出外部类静态变量out_Static_int:3
外部类的outStaticMethod静态方法

(3)方法内部类
方法内部类不允许使用访问权限修饰符(public、private、protected)均不允许
方法内部类对外部完全隐藏,除了创建这个类的方法可以访问它以外,其他地方均不能访问
局部内部类类似方法的局部变量,所以在类外或者类的其他方法中不能访问这个内部类,但这并不代表局部内部类的实例和定义了它的方法中的局部变量具有相同的生命周期
局部内部类可以使用final 或 abstract修饰,不能在局部内部类中使用可变的局部变量(即用final修饰局部变量)

/**
 *	外部类、内部类
 */
public class OutClass {
	/**
     * 外部类定义的属性
     */
    private int out_int = 1;
    private int Class_int = 2;
    /**
     * 静态的属性
     */
    private static int out_Static_int = 3;
    /**
     * 成员外部方法
     */
    public void outClassMethod() {
        System.out.println("外部类outClassMethod方法");
    }
    /**
     * 静态外部方法
     */
    public static void outStaticMethod() {
        System.out.println("外部类outStaticMethod静态方法");
    }
    
    /**
     * 成员方法,内部定义局部内部类
     */
    public void outInsideMethod(int value) {
    	
        boolean sex = false;
        /**
         * 局部内部类,类前不能有访问修饰符
         */
        class InClass {

            private int in_int = 10;
            private int Class_int = 20;
			/**
			*	局部内部类方法
			*/
            public void inClassShow() {
                System.out.println("输出变量in_int:" + in_int);
                //局部变量
                System.out.println("输出boolean变量:" + sex);
                System.out.println("参数value:" + value);
                //调用外部类的信息
                System.out.println("输出变量out_int:" + out_int);
                System.out.println("输出内部类Class_int:" + Class_int);
                System.out.println("输出外部类Class_inte:" + OutClass.this.Class_int);
                System.out.println("输出外部类静态变量out_Static_int:" + out_Static_int);
                //调用外部类的方法
                outClassMethod();
                outStaticMethod();
            }
        }
        //局部内部类只能在方法内使用
        InClass inner = new InClass();
        inner.inClassShow();
    }
    /**
     * main方法
     */
    public static void main(String[] args) {
        OutClass out = new OutClass();
        out.outInsideMethod(100);
    }
}

(4)匿名内部类
匿名内部类就是一个没有名字的方法内部类,因此特点和方法与方法内部类完全一致,除此之外,还有自己的特点:

  • 匿名内部类必须继承一个抽象类或者实现一个接口,但是不能两者兼备,而且实现接口也只能实现一个接口
    注意:不论是继承父类,还是实现接口,实际上拿到的是父类或接口的引用。这个父类引用实际指向的是一个由匿名内部类定义的类的实例。因此,这个被继承的父类(或接口)必须是事先存在的。否则,编译器会提示你创建这个类
  • 匿名内部类没有类名,因此没有构造方法,但可通过实例初始化块 来达到构造器的效果,但是也不能重载实例初始化方法
  • 匿名内部类中的方法都是通过父类引用访问的,所以,如果定义了一个在父类中没有的方法,那么这个方法是不能被这个父类引用调用到的
    由于匿名内部类不利于代码的重用,因此,一般在确定此内部类只会使用一次时,才会使用匿名内部类
/**
*	接口中方法默认为public 
*/
interface Test_interface{
	void Test();
}
/**
*	外部内、内部类
*/
public class OutClass {

    public static Test_interface getInClassInstance(final String Test){
        return new Test_interface(){
            @Override
            public void Test(){
                System.out.println(Test);
            }};
     
    }
    
    public static void main(String[] args){
    	//调用的Test是重写后的Test方法。
        OutClass.getInClassInstance("TEST").Test();
    }
}

为什么要使用内部类

使用内部类;

class OutClass{
    private String out_str ="外部类String";
    //定义一个内部类
    class InClass{
        private String in_Str= "内部类String";
        //定义一个方法,调用外部类的str属性
        public void outprint(){
            System.out.println(out_str);
        }
    }
    //在外部类中定义一个方法,该方法负责产生内部类对象并调用outprint()方法
    public void fun(){
        //内部类对象
        InClass in = new InClass();
        in.outprint();
    }
}
public class Test{
    public static void main(String[] args)
    {
        //创建外部类对象
    	OutClass out = new OutClass();
        //调用外部类方法
        out.fun();
    }
}

未使用内部类:

class OutClass{
    private String out_Str ="Outer类Str";
    public String getOutStr()
    {
        return out_Str;
    }
    public void fun(){  
        //this表示当前outClass对象
        InClass in = new InClass(this); 
        in.printout();                 
    }
}
class InClass{
    private String in_Str= "InClass类str";
    private OutClass out;
    
    public InClass(OutClass out)  
    {
        this.out=out;      //为InClass中的out变量初始化
    }
    public void printout(){    
        System.out.println(out.getOutStr());
    }
} 
public class Test{
    public static void main(String[] args)
    {
        OutClass out = new OutClass(); 
        out.fun(); 
    }
}

虽然返回结果相同,但很明显去掉内部类之后发现程序更加难以理解

内部类用法

实现多重继承

class B{
	public void testB(){
		System.out.println("这是未重写的testB方法");
	}
}
class C{
	public void testC(){
		System.out.println("这是未重写的testC方法");
	}
}

class A{
	private class InnerB extends B{
		@Override
		public void testB() {
			System.out.println("这是重写之后的testB方法");
		}
	}
	//通过内部类InnerB继承B来重写testB()方法
	private class InnerC extends C{
		@Override
		public void testC() {
			System.out.println("这是重写之后的testC方法");
		}
	}
	//通过内部类InnerC继承B来重写testC()方法
	public void testB(){
		new InnerB().testB();
	}
	public void testC(){
		new InnerC().testC();
	}
	//再通过new出两个内部类的对象来调用内部类中被重写的方法
}
public class Innerclass_extend{
	public static void main(String[] args) {
		A a = new A();
		a.testB();
		a.testC();
	}
}

#静态内部类实现延时加载单例模式

public class SingletonIniti {
        private SingletonIniti() {
        }
        private static class SingletonHolder {
                private static final SingletonIniti INSTANCE = newSingletonIniti();
         }
        public static SingletonIniti getInstance() {
                return SingletonHolder.INSTANCE;
        }
}

当getInstance方法第一次被调用的时候,它第一次读取SingletonHolder.instance,内部类SingletonHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Singleton的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性
这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值