Java内部クラスの使用方法

WBOY
リリース: 2023-04-20 18:07:07
転載
1485 人が閲覧しました

    1. 内部クラスの紹介

    1. 概念

    Java では、通常、パッケージ内の異なる場所に異なるクラスを作成します。同じパッケージ内のクラスの場合、それらはすべて同じレベルになります。しかし、実際には別の状況があります。一部のクラスは別のクラス内で定義できます。クラス内で定義されたクラスを内部クラス (InnerClass) またはネストされたクラスと呼び、外部で定義されたクラスを外部クラス (OutClass) またはホスト クラスと呼びます。 つまり、メンバー変数とメソッドは、他のクラスと同様にクラス内でも定義できます。内部クラスを定義するための一般的な形式は次のとおりです。

    class Outer {//外部类
        
        class Inner {//内部类
            
            //方法和属性
        }
        
    }
    ログイン後にコピー

    上記のコードでは、Outer は通常の外部クラス、Inner は内部クラスです。 通常の外部クラスとの最大の違いは、そのインスタンス オブジェクトが単独で存在できず、外部クラスのインスタンス オブジェクトにアタッチする必要があることです。

    内部クラスは適切に非表示にすることができます。通常、非内部クラスはプライベートおよび保護されたアクセス許可を持つことができませんが、内部クラスには許可されており、内部クラスは外部クラスのアクセス許可も持ちます。すべての要素に対するアクセス許可。つまり、内部クラスのアクセス ルールの多くは変数とメソッドを参照できます。

    ただし、プログラム構造をよりコンパクトにするために内部クラスを使用しますが、オブジェクト指向の考え方がある程度破壊されることに注意してください。

    2. 利点

    内部クラスの存在には、次のような利点があります:

    • 内部クラスにより、複数の問題に対する解決策が可能になります。継承の完全性の向上: 各内部クラスは独立してインターフェイスを実装できます。外部クラスがインターフェイスを実装しているか、親クラスを継承しているかに関係なく、内部クラスには影響しません。

    • #両方 特定の論理関係を持つクラスをまとめて整理し、それらを外界から隠すと便利です;

    • あらゆる種類のイベント駆動型プログラムを作成するのに便利です;

    • スレッドコードを記述するのに便利です。

    3. 分類

    Java の内部クラスは次のタイプに分類できます:

    • メンバー内部クラス

    • 静的内部クラス

    • 部分内部クラス

    • 匿名内部クラス

    内部クラスはほとんどの場合あまり使用されませんが、具体的にどのように使用されるかを理解する必要もあります。

    4. 内部クラスの特性

    外部クラスと比較して、内部クラスには次の特徴があります:

    • 内部クラスは外部クラスのプライベート メンバーにアクセスできます。カプセル化を破壊せずにクラスを作成します;

    • 内部クラスはまだ独立した​​クラスです。コンパイル後、内部クラスは独立した .class ファイルにコンパイルされますが、その前に外部クラス。クラス名と $ 記号のファイル名の形式は、外部クラス名 $ 内部クラス名.class;

    • 内部クラスは外部クラスのメンバーであるため、 、内部クラスは通常のアクセスを使用できませんが、内部クラスは、プライベートに変更されているかどうかに関係なく、外部クラスのメンバー変数に自由にアクセスできます。クラスでは、外部クラスのメンバーに自由にアクセスできません。変数は外部クラスの静的メンバー変数にのみアクセスできます。

    • #5. Java クラス作成の要件
    • Java クラスを作成および定義するときは、次の要件に従う必要があります:

    Java ファイルには複数のクラスを記述することができますが、public キーワードを使用して変更できるのは、メイン クラスと呼ばれる 1 つのクラスのみです。

      メイン クラス名は一貫している必要があります。ファイル名が の場合、開発中は 1 つの Java ファイルに 1 つのクラスのみを記述するようにしてください。
    • 外部クラスにはパブリックとデフォルトの 2 つのアクセス レベルのみがあり、内部クラスには 4 つのアクセスがあります。レベル: public、protected、private、default;
    • #外部クラスでは、内部クラスのクラス名を通じて内部クラスに直接アクセスできます;
    • 外部クラス以外のクラスでは、内部クラスの完全なクラス名を使用して内部クラスにアクセスする必要があります。
    • 内部クラスと外部クラスはアクセスできません。同じ名前を持っています。
    • 次に、上記のいくつかの内部クラスについて、これらの内部クラスの使用法を説明します。
    • 2. メンバー内部クラス

      1. 概念

    メンバー内部クラスは、static によって変更されていない内部クラスを指し、呼び出すこともできます。非静的内部クラス。

    2. 機能

    メンバー内部クラスには次の機能があります:

    初期の JDK バージョンでは、非静的プロパティとメソッドは、final と static で同時に変更されない限り、メンバーの内部クラスで定義できます;

    jdk の新しいバージョンでは、静的プロパティとメソッドプロパティとメソッド;
    • メンバー内部クラスは、複数のレベルでネストされている場合でも、プライベート メンバーや静的メンバーを含む外部クラスのすべてのメンバーにアクセスできます。
    • 外部クラスは内部クラスのメンバーに直接アクセスできず、内部クラスのインスタンス オブジェクトを通じてアクセスする必要があります。外部クラスの静的メソッドと外部クラス以外のクラスの場合、内部クラスのインスタンス オブジェクトは外部クラスのインスタンスを通じて作成する必要があります;
    • 外部类的实例与内部类实例是一对多的关系,即一个内部类实例只对应一个外部类实例,但一个外部类实例则可以对应多个内部类实例。

    3. 语法

    如果是在外部类中,创建成员内部类对象的基本语法格式如下:

    内部类 对象名 = new 内部类();

    如果是在外部的其他类中,或者是在外部类的静态方法中,创建成员内部类对象的基本语法格式如下:

    内部类 对象名 = new 外部类().new 内部类();

    4. 案例

    4.1 定义成员内部类

    /**
     * 成员内部类
     */
    public class OuterClass {
    
    	// 外部类的非静态成员
    	String name = "一一哥";
    	private String hobby = "撸码";
    	static int age = 30;
    
    	// 非静态方法
    	public void show() {
    		//这里的this是指OuterClass对象
    		System.out.println("show方法...name="+this.name);
    
            //如果是在外部类里面创建内部类的对象,就不需要创建外部类实例,可以直接new 内部类()
    		//InnerClass inner = new InnerClass();
    	}
    
    	// 定义一个成员内部类
    	public class InnerClass {
    		// 也可以定义私有属性
    		private int a = 10;
    
    		//在早期的JDK中,成员内部类中不能定义静态变量;但在新版JDK中,成员内部类中可以定义静态变量
    		static int b = 20;
    
    		// 非静态方法
    		public void m1() {
    			// 这里的this对象是InnerClass内部类对象
    			System.out.println("成员内部类的成员变量:" + this.a);
    			
    			//外部类.this.属性或方法,这个this是外部类对象
    			System.out.println("外部类的成员变量:" + OuterClass.this.name);
    			
                //内部类中可以访问外部类的私有成员和静态成员
    			System.out.println("外部类的私有成员变量:" + hobby);
    			System.out.println("外部类的静态变量:" + age);
    		}
    
    		//在早期的JDK中,成员内部类中不能定义静态方法;但在新版JDK中,成员内部类中可以定义静态方法
    		public static void m2() {
    			System.out.println("调用成员内部类的静态变量:" + b);
    			System.out.println("调用外部类的静态变量:" + age);
    
                //在静态方法中创建内部类对象,也要通过内部类 对象名 = new 外部类().new 内部类();的格式
    			//InnerClass innerClass = new OuterClass().new InnerClass();
    		}
    
    	}
    
    }
    ログイン後にコピー

    我们要注意,在早期的JDK中,成员内部类中不能定义静态属性和方法;但在新版JDK中,成员内部类中可以定义静态的属性和方法。并且我们要搞清楚在不同的位置上,创建内部类对象的方式,以及this的具体含义。

    4.2 定义测试类

    我们在外部的其他类中,要想创建出一个成员内部类的对象,需要通过如下形式:

    内部类 对象名 = new 外部类().new 内部类();

    public class InnerClassTest {
    
    	public static void main(String[] args) {
    		
    		//在外部的其他类中,不能直接创建内部类对象,否则:
    		//No enclosing instance of type OuterClass is accessible. 
    		//Must qualify the allocation with an enclosing instance of type OuterClass 
    		//(e.g. x.new A() where x is an instance of OuterClass).
    		//InnerClass inner=new InnerClass();
    
            //在外部的其他类中创建内部类对象,需要通过如下格式:
    		//内部类 对象名 = new 外部类().new 内部类();
    		//InnerClass inner=new OuterClass().new InnerClass();
    		
    		//也可以拆分成如下格式:
    		OuterClass outer=new OuterClass();
    		InnerClass inner=outer.new InnerClass();
    		
    		inner.m1();
    		
    		InnerClass.m2();
    		
    	}
    }
    ログイン後にコピー

    5. 访问方式小结

    学习到这里,你可能会被内部类与外部类之间的调用访问关系整蒙圈,所以给大家梳理了一下访问方式:

    • 成员内部类 访问 外部类的成员(属性、方法),可以【直接访问使用】;

    • 外部类 访问 成员内部类,需要【直接创建内部类对象后再访问】,即 new InnerClass();

    • 外部的其他类 访问 成员内部类,需要【创建外部类对象,再创建内部类对象后访问】,即 InnerClass inner=new OuterClass().new InnerClass();

    6. 关于this的注意事项

    在之前给大家讲过this的作用和用法,但在内部类中,关于this,我们需要注意以下两点:

    如果同时存在外部类和内部类,那么this在哪个类中使用,this就代表哪个类的对象;

    如果内部类想要通过this来调用外部类的属性和方法,需要使用外部类名.this.属性或者方法名。

    三. 局部内部类

    1. 概念

    局部内部类是指在方法中定义的内部类。

    2. 特点

    局部内部类具有如下特点:

    • 局部内部类只能在方法中定义和创建对象,也只在当前方法中有效;

    • 局部内部类中可以访问外部类的所有成员;

    • 局部内部类与局部变量一样,不能使用访问控制修饰符(public、private和protected)和static修饰符;

    • 在jdk 7版本中,如果局部变量是在局部内部类中使用,必须显式地加上final关键字;在jdk 8版本中,会默认添加final关键字;

    • 局部内部类只能访问当前方法中final类型的参数与变量。如果方法中的成员与外部类的成员同名,可以使用 .this. 的形式访问外部类成员;

    • 局部内部类中还可以包含内部类,但这些内部类也不能使用访问控制修饰符(public、private 和 protected) 和 static修饰符;

    • 局部变量在方法执行结束后会被销毁,而局部内部类的对象会等到内存回收机制进行销毁。如果是局部内部类里的常量,该常量会被存放在常量池中。

    3. 语法

    创建局部内部类对象的基本语法格式如下:

    public class PartClass {
        
        public void method() {
            //在方法中定义的内部类,就是局部内部类
            class Inner {
                //属性
    
                //方法
            }
        }
        
    }
    ログイン後にコピー

    4. 案例

    4.1 定义局部内部类

    我们来定义一个局部内部类的案例代码。

    /**
     * 
      * 局部内部类---定义在方法中的内部类
     */
    public class PartOuterClass {
    
    	//类的成员变量
    	String name="一一哥";
        private int age=30;
        static String hobby="java";
        
        public void show() {
        	//局部变量
            //JDK 7之前,匿名内部类和局部内部类中访问外部的局部变量时,该变量需要明确地带有final修饰符
            //final int num = 10;
            
            //Effectively final特性
            int num = 10;
            
            //局部内部类,类似于是方法中的局部对象
            class PartInnerClass{
            	
            	//内部可以正常定义方法
                public void m1() {
                	//访问外部类的非静态成员,可以使用OuterClass.this.成员的格式,也可以直接访问
                	//System.out.println("外部类的成员变量"+name);
                    System.out.println("外部类的成员变量"+PartOuterClass.this.name);
                    System.out.println("外部类私有的成员变量"+age);
                    System.out.println("外部类的静态变量"+hobby);
                    
                    //局部内部类,可以直接访问方法中的局部变量
                    System.out.println("访问局部变量"+num);
                }
                
                //在新版的jdk中,也可以定义静态的属性和方法,老版的jdk则不行
                static int b=10;
                
                public static void m2() {
                	System.out.println("外部类的静态变量,hobby="+hobby+",b="+b);
                }
            }
            
            //创建局部内部类对象
            PartInnerClass inner = new PartInnerClass();
            inner.m1();
            
            //在当前类中,局部内部类可以直接访问静态成员
            PartInnerClass.m2();
            
        }    
        
    }
    ログイン後にコピー

    在JDK 7之前,匿名内部类和局部内部类中访问外部的局部变量时,该变量需要明确地带有final修饰符。但从JDK 8之后,我们可以不带final修饰符,而是由系统默认添加了。

    4.2 定义测试类

    接下来我们对上面的案例进行测试。

    public class PartInnerClassTest {
    
    	public static void main(String[] args) {
    		//创建外部类对象,调用方法,执行局部内部类
    		PartOuterClass outer=new PartOuterClass();
    		outer.show();
    	}
    }
    ログイン後にコピー

    4.3 Effectively final特性

    一般情况下,Java中的局部内部类和匿名内部类访问局部变量时,该变量必须由 final修饰,以保证内部类和外部类的数据一致性。但从 Java 8开始,我们可以不加 final修饰符,而是由系统默认添加,当然这在 Java 8以前是不允许的。Java将这个新的特性称为 Effectively(有效的、实际的) final 功能

    另外在 Lambda表达式中,使用局部变量时也要求该变量必须是 final 修饰的,所以 effectively final特性在 Lambda表达式的上下文中非常有用。

    其实effectively final特性,只是让我们不用显式地把变量声明为final修饰的,它给我们自动添加了final修饰词,但并没有取消final,主要是减少了一点不必要的操作,给开发节省了点时间。

    四. 匿名内部类

    1. 概念

    匿名内部类就是指没有类名的内部类,必须在创建时使用 new 语句来声明。匿名内部类不能在Outer Class外部类中定义,而是要在某个方法的内部,通过匿名类(Anonymous Class)的形式来定义。 匿名内部类本身就是一个对象。

    通常情况下,如果一个方法的参数是接口类型,且该接口只需要实现一次,那么我们就可以通过匿名内部类的形式来进行定义。另外如果该接口的实现每次都不同,也可以使用匿名内部类的形式进行定义。我们也可以把这种定义形式叫做 “接口回调” 。匿名内部类的代码格式使得代码更加简洁、紧凑,模块化程度也更高。

    2. 特点

    匿名内部类具有如下特点:

    • 匿名内部类本身就是一个对象;

    • 一般在匿名内部类中不会定义属性和方法,因为没有意义;

    • 匿名内部类的父类一般都是抽象类或者是接口;

    • 匿名内部类和局部内部类一样,可以访问外部类的所有成员;

    • 如果匿名内部类位于方法中,则该类只能访问方法中 final 类型的局部变量和参数;

    • 匿名内部类中允许使用非静态代码块对成员进行初始化操作;

    • 匿名内部类的非静态代码块会在父类的构造方法之后被执行。

    3. 语法

    通常匿名内部类有两种实现方式:

    • 继承一个类,重写其方法;

    • 实现一个或多个接口,并实现其方法。

    创建匿名内部类对象的基本语法格式如下:

    new <类或接口> (){
    重写类或接口的方法
    }

    4. 案例

    为了给大家演示匿名内部类的用法,接下来壹哥设计一个用于模拟按钮点击事件的案例。当我们进行安卓等设备开发时,面板上有个按钮,点击该按钮,如何监听点击事件?在Android系统中提供了各种对应的按钮点击监听事件。所以这里壹哥就通过实现接口的形式来定义匿名内部类,模拟一个单击事件。

    4.1 定义接口

    首先我们需要定义一个接口,表示单击监听,内部有个点击事件。

    /**
     * 点击监听事件
     */
    public interface OnClickListener {
    
    	//点击事件
    	void onClick();
    	
    }
    ログイン後にコピー

    4.2 定义Button按钮类

    然后定义一个Button按钮类,给Button按钮安排一个点击监听方法。

    /**
     * 
     * 局部内部类---定义在方法中的内部类
     */
    public class Button {
    
    	//处理案例点击的监听事件
        public void setOnClickListener(OnClickListener listener) {
        	
        	listener.onClick();
        }
        
    }
    ログイン後にコピー

    4.3 定义测试类

    接下来我们就测试运行上面的代码。

    /**
     * 匿名内部类测试
     */
    public class AnonyInnerClassTest {
    
    	public static void main(String[] args) {
    		//外部变量
    		int num=20;
    		
    		//测试匿名内部类
    		Button btn=new Button();
    		
    		//模拟处理按钮的点击事件
    		btn.setOnClickListener(new OnClickListener() {//这里就是一个匿名内部类
    			
    			//在匿名内部类中,可以允许使用非静态代码块进行成员初始化操作。
    			int i; 
    			
    			{    // 非静态代码块,在构造方法之后执行
    		        i = 100;    //成员初始化
    		    }
    			
    			@Override
    			public void onClick() {
    				System.out.println("按钮被点击啦...i="+i+",num="+num);
    			}
    		});
    		
    	}
    }
    ログイン後にコピー

    根据上面的案例可知:

    • 在匿名内部类中,可以允许使用非静态代码块进行成员初始化操作;

    • 匿名内部类的非静态代码块,会在构造方法之后执行;

    • 匿名内部类也可以直接使用外部类的成员。

    五. 静态内部类

    1. 概念

    静态内部类和成员内部类的定义类似,但要使用static修饰,所以称为静态内部类(Static Nested Class)。

    静态内部类和成员内部类有很大的不同,它不再依附于Outer的实例,而是一个完全独立的类,因此无法引用Outer.this的方式调用。但它可以访问Outer类的private静态字段和静态方法,如果我们把静态内部类移到Outer类之外,就失去了访问private的权限。

    2. 特点

    静态内部类中可以定义非静态的属性和方法,也可以定义静态的属性和方法;

    静态内部类中只能访问静态外部类的静态属性和方法。

    3. 语法

    创建静态内部类对象的基本语法格式如下:

    内部类 对象名 = new 外部类.内部类();

    4. 案例

    4.1 定义静态内部类

    这里我们先简单定义一个静态内部类,后面我们在学习内部类时再专门讲解。在这个静态内部类中,定义了一个方法,来访问外部类中的普通属性和静态属性。我们要记住以下几点:

    • 静态内部类访问外部类的成员变量时,需要先创建外部类对象;

    • 非静态内部类可以直接访问使用外部类的成员变量,如同使用本类中的变量;

    • 所有的内部类访问外部类的静态变量时,可以直接通过"外部类.静态变量"的形式访问。

    /**
     * 外部类和内部类
     */
    public class OuterClass {
    	
    	//普通属性,属于外部类
    	static int outerNum=10;
    	
    	//定义一个静态的内部类,如果不带static,就是一个普通的内部类。
    	//内部类的使用,和普通类一样,里面可以正常定义属性、方法、构造方法等。
        //static前面可以带public等任意访问修饰符,也可以不带!
    	static class InnerClass{
    		//私有属性无法在类的外部直接访问
    		//private int innerNum=20;
    		
    		int innerNum=20;
    		
    		public void printNum() {
    			//定义外部类对象
    			OuterClass outer=new OuterClass();
    
                //这里的this是指InnerClass内部类对象!
    			System.out.println("innerNum="+this.innerNum+",outerAge="+outer.outerAge+",outerNum="+OuterClass.outerNum);
    		}
    	}
    
    }
    ログイン後にコピー

    对于静态内部类而言,static前面可以带public等任意访问修饰符,也可以不带!

    4.2 定义测试类

    我们再定义一个测试类,看看内部类对象是怎么调用的。

    /**
     * 测试访问内部类
     */
    public class InnerClassTest {
    	
    	public static void main(String[] args) {
    		//创建内部类对象,格式为“外部类.内部类 对象名 = new 外部类.内部类的构造方法”
    		OuterClass.InnerClass inner = new OuterClass.InnerClass();
    		
    		//调用内部类的方法
    		inner.printNum();
    		
    		//访问外部类属性
    	    System.out.println("outerNum="+OuterClass.outerNum);
    	    
    	    //访问内部类属性
    	    System.out.println("innerNum="+inner.innerNum);
    	}
    
    }
    ログイン後にコピー

    5. 访问方式小结

    对于静态内部类的访问要求,给大家总结如下:

    • 静态内部类中可以直接访问外部类的所有静态方法,包含私有的,但不能直接访问非静态成员;

    • 静态内部类可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员;

    • 如果静态内部类 访问 外部类 的静态属性、静态方法等,访问方式是【直接访问】;

    • 如果外部类或外部的其他类来 访问 静态内部类,访问方式是【外部类.内部类 对象名 = new 外部类.内部类的构造方法】,创建出内部类对象后再访问

    以上がJava内部クラスの使用方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    関連ラベル:
    ソース:yisu.com
    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    人気のチュートリアル
    詳細>
    最新のダウンロード
    詳細>
    ウェブエフェクト
    公式サイト
    サイト素材
    フロントエンドテンプレート