2023年6月20日发(作者:)
javanew⼀个内部类_java内部类java内部类的⼏种类型:成员内部类,静态内部类,⽅法内部类,匿名内部类。成员内部类:成员内部类是类内部的⾮静态类。成员内部类不能定义静态⽅法和变量(final修饰的除外)。这是因为成员内部类是⾮静态的,类初始化的时候先初始化静态成员,如果允许成员内部类定义静态变量,那么成员内部类的静态变量初始化顺序是有歧义的。例⼦如下:运⾏结果为:访问外部类中的a:99,访问内部类中的b:2成员内部类的使⽤⽅法:1、 Inner 类定义在 Outer 类的内部,相当于 Outer 类的⼀个成员变量的位置,Inner 类可以使⽤任意访问控制符,如 public 、protected 、 private 等2、 Inner 类中定义的 test() ⽅法可以直接访问 Outer 类中的数据,⽽不受访问控制符的影响,如直接访问 Outer 类中的私有属性a3、 定义了成员内部类后,必须使⽤外部类对象来创建内部类对象,⽽不能直接去 new ⼀个内部类对象,即:内部类 对象名 = 外部类对象.new 内部类( );4、 编译上⾯的程序后,会发现产⽣了两个 .class ⽂件其中,第⼆个是外部类的 .class ⽂件,第⼀个是内部类的 .class ⽂件,即成员内部类的 .class ⽂件总是这样:外部类名$内部类名.class另外,友情提⽰哦:1、 外部类是不能直接使⽤内部类的成员和⽅法滴。如:那么外部类如何使⽤内部类的成员和⽅法呢??答:可先创建内部类的对象,然后通过内部类的对象来访问其成员变量和⽅法。Java 编译器在创建内部类对象时,隐式的把其外部类对象的引⽤也传了进去并⼀直保存着。这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部 类作⽤范围之外向要创建内部类对象必须先创建其外部类对象的原因。2、 如果外部类和内部类具有相同的成员变量或⽅法,内部类默认访问⾃⼰的成员变量或⽅法,如果要访问外部类的成员变量,可以使⽤this 关键字。如:运⾏结果:静态内部类:静态内部类是 static 修饰的内部类,这种内部类的特点是:1、 静态内部类不能直接访问外部类的⾮静态成员,但可以通过new 外部类().成员 的⽅式访问。2、 如果外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员;如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调⽤外部类的静态成员。3、 创建静态内部类的对象时,不需要外部类的对象,可以直接创建 内部类 对象名= new 内部类();运⾏结果 :
⽅法内部类:⽅法内部类就是内部类定义在外部类的⽅法中,⽅法内部类只在该⽅法的内部可见,即只在该⽅法内可以使⽤。⼀定要注意哦:由于⽅法内部类不能在外部类的⽅法以外的地⽅使⽤,因此⽅法内部类不能使⽤访问控制符和 static 修饰符。匿名内部类:匿名类是不能有名称的类,所以没办法引⽤他们。必须在创建时,作为new语句的⼀部分来声明他们。但使⽤匿名内部类还有个前提条件:必须继承⼀个⽗类或实现⼀个接⼝。这就要采⽤另⼀种形式 的new语句,如下所⽰:new这种形式的new语句声明⼀个 新的匿名类,他对⼀个给定的类进⾏扩展,或实现⼀个给定的接⼝。他还创建那个类的⼀个新实例,并把他作为语句的结果⽽返回。要扩展的类和要实现的接⼝是new语句的操作数,后跟匿名类的主体。注意匿名类的声明是在编译时进⾏的,实例化在运⾏时进⾏。这意味着for循环中的⼀个new语句会创建相同匿名类的⼏个实例,⽽不是创建⼏个不同匿名类的⼀个实例。从技术上说,匿名类可被视为⾮静态的内 部类,所以他们具备和⽅法内部声明的⾮静态内部类相同的权限和限制。假如要执⾏的任务需要⼀个对象,但却不值得创建全新的对象(原因可能 是所需的类过于简单,或是由于他只在⼀个⽅法内部使⽤),匿名类就显得很有⽤。匿名类尤其适合在Swing应⽤程式中快速创建事件处理程式。以下是⼀个匿名内部类的实例:1、匿名内部类的基本实现:运⾏结果:可以看到,我们直接将抽象类Person中的⽅法在⼤括号中实现了,这样便可以省略⼀个类的书写,并且,匿名内部类还能⽤于接⼝上。2、在接⼝上使⽤匿名内部类:运⾏结果:由上⾯的例⼦可以看出,只要⼀个类是抽象的或是⼀个接⼝,那么其⼦类中的⽅法都可以使⽤匿名内部类来实现。在使⽤匿名内部类的过程中,我们需要注意如下⼏点:1、使⽤匿名内部类时,我们必须是继承⼀个类或者实现⼀个接⼝,但是两者不可兼得,同时也只能继承⼀个类或者实现⼀个接⼝。2、匿名内部类中是不能定义构造函数的。3、匿名内部类中不能存在任何的静态成员变量和静态⽅法。4、匿名内部类为局部内部类(即⽅法内部类),所以局部内部类的所有限制同样对匿名内部类⽣效。5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接⼝的所有抽象⽅法。匿名内部类重点难点:1. 如果是在⼀个⽅法的匿名内部类,可以利⽤这个⽅法传进你想要的参数,不过记住,这些参数必须被声明为final 。使⽤的形参为何要为final??我们给匿名内部类传递参数的时候,若该形参在内部类中需要被使⽤,那么该形参必须要为final。也就是说:当所在的⽅法的形参需要被内部类⾥⾯使⽤时,该形参必须为final。⾸先我们知道在内部类编译成功后,它会产⽣⼀个class⽂件,该class⽂件与外部类并不是同⼀class⽂件,仅仅只保留对外部类的引⽤。当外部类传⼊的参数需要被内部类调⽤时,从java程序的⾓度来看是直接被调⽤:public class OuterClass {public void display(final String name,String age){class InnerClass{void display(){n(name);}}}}从上⾯代码中看好像name参数应该是被内部类直接调⽤?其实不然,在java编译之后实际的操作如下:public class OuterClass$InnerClass {public InnerClass(String name,String age){lass$name = name;lass$age = age;}public void display(){n(lass$name + "----" + lass$age );}}所以从上⾯代码来看,内部类并不是直接调⽤⽅法传递的参数,⽽是利⽤⾃⾝的构造器对传⼊的参数进⾏备份,⾃⼰内部⽅法调⽤的实际上时⾃⼰的属性⽽不是外部⽅法传递进来的参数。直到这⾥还没有解释为什么是final。在内部类中的属性和外部⽅法的参数两者从外表上看是同⼀个东西,但实际上却不是,所以他们两者是可以任意变化的,也就是说在内部类中我对属性的改变并不会影响到外部的形参,⽽然这从程序员的⾓度来看这是不可⾏的,毕竟站在程序的⾓度来看这两个根本就是同⼀个,如果内部类该变了,⽽外部⽅法的形参却没有改变这是难以理解和不可接受的,所以为了保持参数的⼀致性,就规定使⽤final来避免形参的不改变。简单理解就是,拷贝引⽤,为了避免引⽤值发⽣改变,例如被外部类的⽅法修改等,⽽导致内部类得到的值不⼀致,于是⽤final来让该引⽤不可改变。故如果定义了⼀个匿名内部类,并且希望它使⽤⼀个其外部定义的参数,那么编译器会要求该参数引⽤是final的。2. 匿名内部类中使⽤初始化代码块我们⼀般都是利⽤构造器来完成某个实例的初始化⼯作的,但是匿名内部类是没有构造器的!那怎么来初始化匿名内部类呢?使⽤构造代码块!利⽤构造代码块能够达到为匿名内部类创建⼀个构造器的效果。public class OutClass {public InnerClass getInnerClass(final int age,final String name){return new InnerClass() {int age_ ;String name_;//构造代码块完成初始化⼯作{if(0 < age && age < 200){age_ = age;name_ = name;}}public String getName() {return name_;}public int getAge() {return age_;}};}public static void main(String[] args) {OutClass out = new OutClass();InnerClass inner_1 = erClass(201, "chenssy");n(inner_e());InnerClass inner_2 = erClass(23, "chenssy");n(inner_e());}}五、内部类总结学习了上⾯四种类型的内部类,我们知道了如何使⽤各个内部类,那么为什么要使⽤内部类呢??⾸先举⼀个简单的例⼦,如果你想实现⼀个接⼝,但是这个接⼝中的⼀个⽅法和你构想的这个类中的⼀个 ⽅法的名称,参数相同,你应该怎么办?这时候,你可以建⼀个内部类实现这个接⼝。由于内部类对外部类的所有内容都是可访问的,所以这样做可以完成所有你直 接实现这个接⼝的功能。不过你可能要质疑,更改⼀下⽅法的不就⾏了吗?的确,以此作为设计内部类的理由,实在没有说服 ⼒。真正的原因是这样的,java中的内部类和接⼝加在⼀起,可以的解决常被C++程序员抱怨java中存在的⼀个问题——没有多继承。实际上,C++的多继承设计起来很复杂,⽽java通过内部类加上接⼝,可以很好的实现多继承的效果。内部类:⼀个内部类的定义是定义在另⼀个内部的类。原因是:1.⼀个内部类的对象能够访问创建它的对象的实现,包括私有数据。2.对于同⼀个包中的其他类来说,内部类能够隐藏起来。3.匿名内部类可以很⽅便的定义回调。4.使⽤内部类可以⾮常⽅便的编写事件驱动程序。内部类可以让你更优雅地设计你的程序结构。下⾯从以下⼏个⽅⾯来介绍:⾸先看这个例⼦:1 public interface Contents {2 int value();3 }45 public interface Destination {6 String readLabel();7 }1 public class Goods {2 private valueRate=2;34 private class Content implements Contents {5 private int i = 11 * valueRate;6 public int value() {7 return i;8 }9 }1011 protected class GDestination implements Destination {12 private String label;13 private GDestination(String whereTo) {14 label = whereTo;15 }16 public String readLabel() {17 return label;18 }19 }2021 public Destination dest(String s) {22 return new GDestination(s);23 }2425 public Contents cont() {26 return new Content();27 }28 }在这个例⼦⾥类 Content 和 GDestination 被定义在了类 Goods 内部,并且分别有着 protected 和 private 修饰符来控制访问级别。Content 代表着 Goods 的内容,⽽ GDestination 代表着 Goods 的⽬的地。它们分别实现了两个接⼝Content和Destination。在后⾯的main⽅法⾥,直接⽤ Contents c 和 Destination d进⾏操作,你甚⾄连这两个内部类的名字都没有看见!这样,内部类的第⼀个好处就体现出来了——隐藏你不想让别⼈知道的操作,也即封装性。⾮静态内部类对象有着指向其外部类对象的引⽤修改上⾯的例⼦:1 public class Goods {2 private valueRate=2;34 private class Content implements Contents {5 private int i = 11 * valueRate;6 public int value() {7 return i;8 }9 }1011 protected class GDestination implements Destination {12 private String label;13 private GDestination(String whereTo) {14 label = whereTo;15 }16 public String readLabel() {17 return label;18 }19 }2021 public Destination dest(String s) {22 return new GDestination(s);23 }2425 public Contents cont() {26 return new Content();27 }28 }在这⾥我们给 Goods 类增加了⼀个 private 成员变量 valueRate,意义是货物的价值系数,在内部类 Content 的⽅法 value() 计算价值时把它乘上。我们发现,value() 可以访问 valueRate,这也是内部类的第⼆个好处——⼀个内部类对象可以访问创建它的外部类对象的内容,甚⾄包括私有变量!这是⼀个⾮常有⽤的特性,为我们在设计时提供了更多的思路和捷径。要想实现这个功能,内部类对象就必须有指向外部类对象的引⽤。Java 编译器在创建内部类对象时,隐式的把其外部类对象的引⽤也传了进去并⼀直保存着。这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部 类作⽤范围之外向要创建内部类对象必须先创建其外部类对象的原因。
2023年6月20日发(作者:)
javanew⼀个内部类_java内部类java内部类的⼏种类型:成员内部类,静态内部类,⽅法内部类,匿名内部类。成员内部类:成员内部类是类内部的⾮静态类。成员内部类不能定义静态⽅法和变量(final修饰的除外)。这是因为成员内部类是⾮静态的,类初始化的时候先初始化静态成员,如果允许成员内部类定义静态变量,那么成员内部类的静态变量初始化顺序是有歧义的。例⼦如下:运⾏结果为:访问外部类中的a:99,访问内部类中的b:2成员内部类的使⽤⽅法:1、 Inner 类定义在 Outer 类的内部,相当于 Outer 类的⼀个成员变量的位置,Inner 类可以使⽤任意访问控制符,如 public 、protected 、 private 等2、 Inner 类中定义的 test() ⽅法可以直接访问 Outer 类中的数据,⽽不受访问控制符的影响,如直接访问 Outer 类中的私有属性a3、 定义了成员内部类后,必须使⽤外部类对象来创建内部类对象,⽽不能直接去 new ⼀个内部类对象,即:内部类 对象名 = 外部类对象.new 内部类( );4、 编译上⾯的程序后,会发现产⽣了两个 .class ⽂件其中,第⼆个是外部类的 .class ⽂件,第⼀个是内部类的 .class ⽂件,即成员内部类的 .class ⽂件总是这样:外部类名$内部类名.class另外,友情提⽰哦:1、 外部类是不能直接使⽤内部类的成员和⽅法滴。如:那么外部类如何使⽤内部类的成员和⽅法呢??答:可先创建内部类的对象,然后通过内部类的对象来访问其成员变量和⽅法。Java 编译器在创建内部类对象时,隐式的把其外部类对象的引⽤也传了进去并⼀直保存着。这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部 类作⽤范围之外向要创建内部类对象必须先创建其外部类对象的原因。2、 如果外部类和内部类具有相同的成员变量或⽅法,内部类默认访问⾃⼰的成员变量或⽅法,如果要访问外部类的成员变量,可以使⽤this 关键字。如:运⾏结果:静态内部类:静态内部类是 static 修饰的内部类,这种内部类的特点是:1、 静态内部类不能直接访问外部类的⾮静态成员,但可以通过new 外部类().成员 的⽅式访问。2、 如果外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员;如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调⽤外部类的静态成员。3、 创建静态内部类的对象时,不需要外部类的对象,可以直接创建 内部类 对象名= new 内部类();运⾏结果 :
⽅法内部类:⽅法内部类就是内部类定义在外部类的⽅法中,⽅法内部类只在该⽅法的内部可见,即只在该⽅法内可以使⽤。⼀定要注意哦:由于⽅法内部类不能在外部类的⽅法以外的地⽅使⽤,因此⽅法内部类不能使⽤访问控制符和 static 修饰符。匿名内部类:匿名类是不能有名称的类,所以没办法引⽤他们。必须在创建时,作为new语句的⼀部分来声明他们。但使⽤匿名内部类还有个前提条件:必须继承⼀个⽗类或实现⼀个接⼝。这就要采⽤另⼀种形式 的new语句,如下所⽰:new这种形式的new语句声明⼀个 新的匿名类,他对⼀个给定的类进⾏扩展,或实现⼀个给定的接⼝。他还创建那个类的⼀个新实例,并把他作为语句的结果⽽返回。要扩展的类和要实现的接⼝是new语句的操作数,后跟匿名类的主体。注意匿名类的声明是在编译时进⾏的,实例化在运⾏时进⾏。这意味着for循环中的⼀个new语句会创建相同匿名类的⼏个实例,⽽不是创建⼏个不同匿名类的⼀个实例。从技术上说,匿名类可被视为⾮静态的内 部类,所以他们具备和⽅法内部声明的⾮静态内部类相同的权限和限制。假如要执⾏的任务需要⼀个对象,但却不值得创建全新的对象(原因可能 是所需的类过于简单,或是由于他只在⼀个⽅法内部使⽤),匿名类就显得很有⽤。匿名类尤其适合在Swing应⽤程式中快速创建事件处理程式。以下是⼀个匿名内部类的实例:1、匿名内部类的基本实现:运⾏结果:可以看到,我们直接将抽象类Person中的⽅法在⼤括号中实现了,这样便可以省略⼀个类的书写,并且,匿名内部类还能⽤于接⼝上。2、在接⼝上使⽤匿名内部类:运⾏结果:由上⾯的例⼦可以看出,只要⼀个类是抽象的或是⼀个接⼝,那么其⼦类中的⽅法都可以使⽤匿名内部类来实现。在使⽤匿名内部类的过程中,我们需要注意如下⼏点:1、使⽤匿名内部类时,我们必须是继承⼀个类或者实现⼀个接⼝,但是两者不可兼得,同时也只能继承⼀个类或者实现⼀个接⼝。2、匿名内部类中是不能定义构造函数的。3、匿名内部类中不能存在任何的静态成员变量和静态⽅法。4、匿名内部类为局部内部类(即⽅法内部类),所以局部内部类的所有限制同样对匿名内部类⽣效。5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接⼝的所有抽象⽅法。匿名内部类重点难点:1. 如果是在⼀个⽅法的匿名内部类,可以利⽤这个⽅法传进你想要的参数,不过记住,这些参数必须被声明为final 。使⽤的形参为何要为final??我们给匿名内部类传递参数的时候,若该形参在内部类中需要被使⽤,那么该形参必须要为final。也就是说:当所在的⽅法的形参需要被内部类⾥⾯使⽤时,该形参必须为final。⾸先我们知道在内部类编译成功后,它会产⽣⼀个class⽂件,该class⽂件与外部类并不是同⼀class⽂件,仅仅只保留对外部类的引⽤。当外部类传⼊的参数需要被内部类调⽤时,从java程序的⾓度来看是直接被调⽤:public class OuterClass {public void display(final String name,String age){class InnerClass{void display(){n(name);}}}}从上⾯代码中看好像name参数应该是被内部类直接调⽤?其实不然,在java编译之后实际的操作如下:public class OuterClass$InnerClass {public InnerClass(String name,String age){lass$name = name;lass$age = age;}public void display(){n(lass$name + "----" + lass$age );}}所以从上⾯代码来看,内部类并不是直接调⽤⽅法传递的参数,⽽是利⽤⾃⾝的构造器对传⼊的参数进⾏备份,⾃⼰内部⽅法调⽤的实际上时⾃⼰的属性⽽不是外部⽅法传递进来的参数。直到这⾥还没有解释为什么是final。在内部类中的属性和外部⽅法的参数两者从外表上看是同⼀个东西,但实际上却不是,所以他们两者是可以任意变化的,也就是说在内部类中我对属性的改变并不会影响到外部的形参,⽽然这从程序员的⾓度来看这是不可⾏的,毕竟站在程序的⾓度来看这两个根本就是同⼀个,如果内部类该变了,⽽外部⽅法的形参却没有改变这是难以理解和不可接受的,所以为了保持参数的⼀致性,就规定使⽤final来避免形参的不改变。简单理解就是,拷贝引⽤,为了避免引⽤值发⽣改变,例如被外部类的⽅法修改等,⽽导致内部类得到的值不⼀致,于是⽤final来让该引⽤不可改变。故如果定义了⼀个匿名内部类,并且希望它使⽤⼀个其外部定义的参数,那么编译器会要求该参数引⽤是final的。2. 匿名内部类中使⽤初始化代码块我们⼀般都是利⽤构造器来完成某个实例的初始化⼯作的,但是匿名内部类是没有构造器的!那怎么来初始化匿名内部类呢?使⽤构造代码块!利⽤构造代码块能够达到为匿名内部类创建⼀个构造器的效果。public class OutClass {public InnerClass getInnerClass(final int age,final String name){return new InnerClass() {int age_ ;String name_;//构造代码块完成初始化⼯作{if(0 < age && age < 200){age_ = age;name_ = name;}}public String getName() {return name_;}public int getAge() {return age_;}};}public static void main(String[] args) {OutClass out = new OutClass();InnerClass inner_1 = erClass(201, "chenssy");n(inner_e());InnerClass inner_2 = erClass(23, "chenssy");n(inner_e());}}五、内部类总结学习了上⾯四种类型的内部类,我们知道了如何使⽤各个内部类,那么为什么要使⽤内部类呢??⾸先举⼀个简单的例⼦,如果你想实现⼀个接⼝,但是这个接⼝中的⼀个⽅法和你构想的这个类中的⼀个 ⽅法的名称,参数相同,你应该怎么办?这时候,你可以建⼀个内部类实现这个接⼝。由于内部类对外部类的所有内容都是可访问的,所以这样做可以完成所有你直 接实现这个接⼝的功能。不过你可能要质疑,更改⼀下⽅法的不就⾏了吗?的确,以此作为设计内部类的理由,实在没有说服 ⼒。真正的原因是这样的,java中的内部类和接⼝加在⼀起,可以的解决常被C++程序员抱怨java中存在的⼀个问题——没有多继承。实际上,C++的多继承设计起来很复杂,⽽java通过内部类加上接⼝,可以很好的实现多继承的效果。内部类:⼀个内部类的定义是定义在另⼀个内部的类。原因是:1.⼀个内部类的对象能够访问创建它的对象的实现,包括私有数据。2.对于同⼀个包中的其他类来说,内部类能够隐藏起来。3.匿名内部类可以很⽅便的定义回调。4.使⽤内部类可以⾮常⽅便的编写事件驱动程序。内部类可以让你更优雅地设计你的程序结构。下⾯从以下⼏个⽅⾯来介绍:⾸先看这个例⼦:1 public interface Contents {2 int value();3 }45 public interface Destination {6 String readLabel();7 }1 public class Goods {2 private valueRate=2;34 private class Content implements Contents {5 private int i = 11 * valueRate;6 public int value() {7 return i;8 }9 }1011 protected class GDestination implements Destination {12 private String label;13 private GDestination(String whereTo) {14 label = whereTo;15 }16 public String readLabel() {17 return label;18 }19 }2021 public Destination dest(String s) {22 return new GDestination(s);23 }2425 public Contents cont() {26 return new Content();27 }28 }在这个例⼦⾥类 Content 和 GDestination 被定义在了类 Goods 内部,并且分别有着 protected 和 private 修饰符来控制访问级别。Content 代表着 Goods 的内容,⽽ GDestination 代表着 Goods 的⽬的地。它们分别实现了两个接⼝Content和Destination。在后⾯的main⽅法⾥,直接⽤ Contents c 和 Destination d进⾏操作,你甚⾄连这两个内部类的名字都没有看见!这样,内部类的第⼀个好处就体现出来了——隐藏你不想让别⼈知道的操作,也即封装性。⾮静态内部类对象有着指向其外部类对象的引⽤修改上⾯的例⼦:1 public class Goods {2 private valueRate=2;34 private class Content implements Contents {5 private int i = 11 * valueRate;6 public int value() {7 return i;8 }9 }1011 protected class GDestination implements Destination {12 private String label;13 private GDestination(String whereTo) {14 label = whereTo;15 }16 public String readLabel() {17 return label;18 }19 }2021 public Destination dest(String s) {22 return new GDestination(s);23 }2425 public Contents cont() {26 return new Content();27 }28 }在这⾥我们给 Goods 类增加了⼀个 private 成员变量 valueRate,意义是货物的价值系数,在内部类 Content 的⽅法 value() 计算价值时把它乘上。我们发现,value() 可以访问 valueRate,这也是内部类的第⼆个好处——⼀个内部类对象可以访问创建它的外部类对象的内容,甚⾄包括私有变量!这是⼀个⾮常有⽤的特性,为我们在设计时提供了更多的思路和捷径。要想实现这个功能,内部类对象就必须有指向外部类对象的引⽤。Java 编译器在创建内部类对象时,隐式的把其外部类对象的引⽤也传了进去并⼀直保存着。这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部 类作⽤范围之外向要创建内部类对象必须先创建其外部类对象的原因。
发布评论