网站没有域名设置,电脑版网页游戏,Wordpress 商城主题过于臃肿,成都装修公司一览表内部类总共有 4 种#xff08;静态内部类、非静态内部类、局部内部类、匿名内部类#xff09; 作用#xff1a;
一#xff1a;内部类提供了更好的封装#xff0c;可以把内部类隐藏在外部类之内#xff0c;不允许同一个包中的其他类访问该类。
二#xff1a;内部类可以…内部类总共有 4 种静态内部类、非静态内部类、局部内部类、匿名内部类 作用
一内部类提供了更好的封装可以把内部类隐藏在外部类之内不允许同一个包中的其他类访问该类。
二内部类可以直接访问外部类的私有数据因为内部类被当成其外部类成员同一个类的成员之间可以互相访问但是外部类不能访问内部类的实现细节例如内部类的成员变量。
三匿名内部类适合用于创建那些只需要创建一次使用的类。
四内部类比外部类可以多使用三个修饰符private、protected、static
五非静态内部类不能拥有静态成员。 1.非静态内部类
非静态内部类定义在外部类里面
public class Demo {private String name;private Integer age;//定义构造器重载public Demo(){}public Demo(String name, Integer age) {this.name name;this.age age;}//定义一个非静态内部类private class InnerDemo {//非静态内部类private double length;private String color;public InnerDemo(){}public InnerDemo(double length, String color) {this.length length;this.color color;}// 此处省略 length 的getter 和 setter 方法.....................//非静态内部类实例方法public void info() {System.out.print(名字是 name : 年龄是: age 肤色是: color 身高是 length);}}public void test() {var innerDemo new InnerDemo(180, 黄);innerDemo.info();}public static void main(String[] args) {Demo demo new Demo(李白 30);demo.test();}}当非静态成员内部类的方法访问某个变量的时候系统优先在该方法内查找是否存在该名字的局部变量如果存在就使用该变量如果不存在则查找该方法所在的内部类中是否存在该名字的成员变量, 如果不存在则到外部类中查找是否存在该名字的成员变量如果依然不存在则会报编译错误提示找不到该变量。
因此如果外部类成员变量、内部类成员变量与内部类里面的方法同名则可以通过使用 this、外部类类名.this 作为限定区分。 可以参考如下模板
public class Demo {private String name 外部类的成员变量;private class InClass {private String name 内部类的成员变量;public void info(){var name 局部变量;System.out.print(外部类的实例变量值: Demo.this.name);//通过 this.varName 访问内部类的成员变量System.out.print(内部类的成员变量: this.name);//直接访问局部变量System.out.print(局部变量的值: name);}}public void test() {var inClass new InClass();inClass.info();}public static void main(String[] args) {Demo demo new Demo();demo.test();}}
2. 静态内部类
使用 static 修饰的内部类被称为静态内部类它属于外部类本身不属于外部类某个实例对象。
静态内部类可以包含静态成员也可以包含非静态成员。根据静态成员不能访问非静态成员的规则静态内部类不能访问外部类的实例成员只能访问外部类的类成员。即使是静态内部类的实例方法也不能访问外部类的实例成员只能访问外部类的静态成员。
public class Demo {private String name 李白;private static int age 2;static class StaticInnerClass {//静态内部类可以包含静态成员private static String womanName 李清照;public void info() {//下面代码出现错误静态内部类不能访问外部类的实例变量System.out.print(name);//下面代码正常System.out.print(age);}}}
静态内部类是外部类的一个成员因此外部类的所有方法、所有初始化块中可以使用静态内部类来定义变量、创建对象等
public class Demo {static class StaticInnerClass {private static int age 10;private String name 李白;}public void info() {//System.out.print(age)//上面代码出现错误应改为如下格式//通过类名访问静态内部类的类成员System.out.print(StaticInnerClass.age);//System.out.print(name);//上面代码出现错误应改为如下格式//通过实例访问静态内部类的实例成员System.out.print(new StaticInnerClass().name);}}
Java 还允许在接口里定义内部类接口里定义的内部类默认使用 public static 修饰也就是说接口内部类只能是静态内部类。 3.使用内部类
1.在外部类内部使用内部类
在外部类内部使用内部类的时与平常使用普通类没有太大的区别。一样可以直接通过内部类类名来定义变量通过 new 调用内部类构造器来创建实例。
唯一的区别是不要在外部类的静态成员包括静态方法和静态初始化中去使用非静态内部类因为静态成员不能访问非静态成员。
在外部类内部定义内部类的子类与平常定义子类也没有太大的区别。
2.在外部类外部使用非静态内部类
如果想在外部类外部使用非静态内部类则内部类不能使用 private 访问控制权限private 修饰的内部类只能在外部类内部使用。对于使用其他访问控制符修饰的内部类则能在访问控制符对应的访问权限内使用。
由于非静态内部类的对象必须寄生在外部类的对象里因此创建非静态内部类对象之前必须先创建其外部类对象。在外部类外面创建内部类实例的语法如下
outerInstance.new InnerContructor();
当创建一个子类的时候子类构造器总会调用父类的构造器因此在创建非静态内部类的子类时必须保证让子类构造器可以调用非静态内部类的构造器调用非静态内部类的构造器时必须存在一个外部类对象
class Out {class Inner {public Inner(String name) {System.out.print(name);}}
}public class Demo extends Out.Inner {//显式定义构造器public Demo(Out out) {out.super(Hello)}}
非静态内部类的子类不一定是内部类它也可以是外部类。但非静态内部类的子类实例一样需要保留一个引用该引用指向其父类所在外部类的对象。也就是说如果有一个内部类子类的对象存在则一定存在与之对应的外部类对象。
3.在外部类以外使用静态内部类。
因为静态内部类是外部类类相关的因此创建静态内部类对象时无需创建外部类对象。创建语法如下
new OutClass.InnerClass();
相比之下使用静态内部类比使用非静态内部类要简单很多只要把外部类当成静态内部类的包空间即可。因此当程序需要使用内部类时应该优先考虑使用静态内部类。
4.局部内部类
把内部类定义在方法里面这个就是局部内部类。局部内部类因为只能在方法里面有效不能在外部类方法以外使用。所以不能使用访问控制符和 static 修饰符修饰。
局部内部类是一份非常鸡肋的语法在实际开发中很少定义局部内部类这是因为局部内部类的作用域太小了只能在当前方法中使用。大部分时候定义一个类之后当然希望多次复用这个类但局部内部类无法离开它所在的方法因此在实际开发中很少使用。
5.匿名内部类
匿名内部类适合创建那种只需要创建一次使用的类匿名内部类不能重复使用。
匿名内部类必须继承一个父类或者实现一个接口但最多只能继承一个父类或实现一个接口。
关于匿名内部类还有如下两条规则
1.匿名内部类不能是抽象类因为系统在创建匿名内部类时会立即创建匿名内部类的对象所以不能把不允许将匿名内部类定义成抽象类。
2.匿名内部类不能定义构造器。由于匿名内部类没有类名所以无法定义构造器但可以定义初始化块可以通过初始化块来完成构造器需要完成的事。
interface Animal {double getPrice();String getName();
}public class Demo {public void test(Animal a) {System.out.print(购买了一个: a.getName() 价格是 a.getPrice());}public static void main(String[] args) {var tar new Demo ();//调用 test()方法时需要传入一个 Animal 参数//此处传入匿名实现类的实例tar.test(new Animal() {public double getPrice() {return 567.9;}public String getName() {return 二哈;}});}}
上面程序中的 Animal 类定义了一个 test()方法该方法需要一个 Animal 对象作为参数但 Animal 只是一个接口无法直接创建对象因此此处创建一个 Animal 接口实现类的对象传入该方法----如果这个 Animal 接口实现类需要重复用则应该将实现类定义为一个独立类如果这个 Animal 接口实现类只需一次使用则可以采用上面程序中的方式定义一个匿名内部类。
定义匿名内部类无需 class 关键字而是在定义匿名内部类的时候直接生成该匿名内部类的对象。
由于匿名内部类不能是抽象类所以匿名内部类必须实现它的抽象类或者接口里面包含的所有抽象方法。
当通过实现接口创建匿名内部类时匿名内部类不能显式地定义构造器因此匿名内部类只有一个隐式的无参构造器故 new 接口名后的括号里不能传入参数值。
但如果是通过继承父类来创建匿名内部类时匿名内部类将拥有和父类相似的构造器此处的相似指的时拥有相同的形参列表。 abstract class Device {private String name;public abstract double getPrice();public Device(){}public Device(String name) {this.name name;}//此处省略 setter 和 getter 方法...}public class AnonymousInner {public void test(Device d) {System.out.print(购买了一个d.getName() , 花掉了d.getPrice());}public static void main(String[] args) {var ai new AnonymousInner();ai.test(new Device(电饭煲) {public double getPrice(){return 500.2;}});//调用无参数的构造器创建Device 匿名实现类的对象var d new Device(){//初始化块{System.out.print(匿名内部类的初始化块....);}//实现抽象方法public double getPrice() {return 56.2;}//重写父类的实例方法public String getName() {return 鼠标;}}ai.test(d);}}
上面的程序创建了一个抽象父类 Device 类这个抽象父类包含两个构造器一个无参数的一个有参数的。当创建以Device 为父类的匿名内部类时既可以传入参数也可以不传入参数。
当创建匿名内部类时必须实现接口或抽象类里面的所有抽象方法。如果有需要也可以重写父类中的普通方法。
在 Java 8 之前Java 要求被局部内部类、匿名内部类访问的局部变量必须使用 final 修饰从 Java 8 开始这个限制被取消了Java 8更加智能如果局部变量被匿名内部类访问那么该局部变量相当于自动加上了 final 修饰。