面向对象(五)

内部类

一个类的内部又完整的嵌套了另一个类结构,被嵌套的类我们称之为内部类。嵌套内部类的类我们称为外部类。内部类最大的特点是可以直接访问私有属性,并且可以体现类与类之间的包含关系

复制
class Outer{//外部类 private int n1 = 100;//成员属性 public void m1(){//成员方法 System.out.println("m1方法"); } {//代码块 System.out.println("代码块"); } public Outer(int n1) {//构造器 this.n1 = n1; } class Inner{//内部类 } }

内部类的分类:
定义在外部类局部位置上(比如方法体内):

  • 局部内部类
  • 匿名内部类(重点!!)

定义在成员属性的位置上:

  • 成员内部类(没有static修饰)
  • 静态内部类(有static修饰)

局部内部类

①定义的位置在局部变量的位置上,一般定义在方法体内部,也可以定义在代码块中,本质仍然是一个类

②可以直接访问外部类的所有属性,包括私有属性

③不能添加访问修饰符,因为局部类部类跟局部变量一样,但是可以使用final修饰

④作用域在定义它的方法体内部

⑤内部类访问外部类的属性直接访问即可

⑥外部类访问内部类的属性,先创建对象,再访问

⑦外部其它类不能访问局部内部类,局部内部类就是一个局部变量

⑧当如果局部内部类和外部类的属性重名,访问的时候遵守就近原则,如果想要访问外部类的属性可以使用外部类名.this.属性
外部类名.this指代的就是正在调用当前内部类包含方法的对象

复制
class Outer2{ private int n1 = 100; private void m2(){ System.out.println("Outer2 m2()"); } public void m1(){ class Inner{//局部内部类,可以直接访问外部类的所有属性,包括私有属性 private int n1 = 800; public void f1(){ System.out.println("n1 = " + n1); //访问同名的外部类属性 System.out.println("Outer2 n1 = " + Outer2.this.n1); m2(); } } //外部类访问局部内部类,直接在方法体内创建对象访问 Inner inner = new Inner(); inner.f1(); } }

匿名内部类(!!!!!)

匿名内部类的初步解读:没有名字;是一个内部类;本质还是类;同时还是一个对象

①匿名内部类使用一次就不能使用

②在jdk底层创建内部类的时候,马上就创建了一个实例

匿名内部类可以简化开发

复制
//基于接口的匿名内部类 interface IA{ public void cay(); } class Outer3{ //外部类 private int n1 = 100; public void m1(){ //tiger的编译类型是tiger //运行时类型是匿名内部类 IA tiger = new IA(){ @Override public void cay() { System.out.println("老虎在叫喊"); } }; tiger.cay(); //tiger的运行时类型:class innerclass.Outer3$1 System.out.println("tiger的运行时类型:" + tiger.getClass()); } }
复制
//基于类的匿名内部类 class Father{ private String name; public Father(String name){ this.name = name; } public void eat(){ } } class Outer3{ //外部类 private int n1 = 100; public void m1(){ //father的编译类型是Father,运行时类型是匿名内部类 //这里的形参列表是传递给Father的构造器 //这里是匿名内部类,不是Father类型 Father father = new Father("jack"){ @Override public void eat() { System.out.println("匿名内部类重写eat方法"); } }; father.eat(); System.out.println("Father的运行时类型:" + father.getClass()); } } //基于抽象类的匿名内部类 class Outer3{ //外部类 private int n1 = 100; public void m1(){ //基于抽象类的匿名内部类,编译类型是Animal,运行时类型是匿名内部类 Animal animal = new Animal() { @Override void eat() { System.out.println("小狗吃骨头"); } }; animal.eat(); } } abstract class Animal{ abstract void eat(); }

④匿名内部类的两种访问方式:

复制
//第一种 Animal animal = new Animal() { @Override void eat() { System.out.println("小狗吃骨头"); } }; animal.eat(); //第二种 new Animal(){ @Override void eat() { System.out.println("小狗吃骨头"); } }.eat();

⑤匿名内部类可以直接访问外部类的所有属性

⑥外部其它类是不能够创建匿名内部类的

⑦匿名内部类的作用域仅仅在它所在的代码块或者方法体中

⑧如果匿名内部类的属性和外部类属性同名,遵守就近原则,如果想要访问外部类的属性可以使用外部类名.this.属性访问

匿名内部类的实践:
1.当做实参传递

复制
public class Demo1 { public static void main(String[] args) { //传入一个匿名内部类对象 f1(new IA(){ @Override public void show() { System.out.println("使用匿名内部类实现传入参数"); } }); } public static void f1(IA ia){ ia.show(); } } interface IA{ public void show(); }

成员内部类

成员内部类定义在外部类的成员属性的位置上,没有static修饰

复制
class Outer4{ private int n1 = 200; private String name = "张三"; public class Inner{ public void m1(){ //访问外部类的私有属性 System.out.println("n1 = " + n1 + " name = " + name); } } public void f1(){ //在外部类方法体内部使用成员内部类 Inner inner = new Inner(); inner.m1(); } }

成员内部类可以访问外部类的所有属性,包括私有属性
成员内部类因为在类成员的位置上面,所有可以使用访问修饰符:public、protected、默认、private修饰
成员内部类的作用域在整个类中,跟其它成员一样
成员内部类访问外部类的属性,直接访问,如果成员内部类和外部类的属性出现同名,遵守就近原则,如果想要访问外部类的属性,可以使用外部类.this.属性
外部类想要访问内部类的属性,先创建实例,再访问,可以访问成员内部类的私有属性,在同一个类中

复制
class Outer4{ private int n1 = 200; private String name = "张三"; public class Inner{ private int n1 = 100; public void m1(){ //访问外部类的私有属性 System.out.println("n1 = " + n1 + " name = " + name); System.out.println("访问外部类属性 n1= " + Outer4.this.n1); } } public void f1(){ //在外部类方法体内部使用成员内部类 Inner inner = new Inner(); inner.m1(); //访问成员内部类的私有属性 System.out.println("成员内部类的 n1 = " + inner.n1); } }

外部其它类想要访问成员内部类有两种方式:

复制
//第一种方式,当成一个成员属性来创建,通过一个外部类的实例 Outer4 outer4 = new Outer4(); Outer4.Inner inner = outer4.new Inner(); inner.m1(); System.out.println("==========="); //第二种方式,在外部类提供一个返回内部类实例的方法 Outer4.Inner inner1 = outer4.getInstanceInner(); inner1.m1();

静态内部类

成员内部类定义在外部类的成员属性的位置上,有static修饰

静态内部类可以访问外部类所有的静态成员,包括私有的
静态内部类可以使用访问修饰符,public,默认,protected,private
静态内部类的作用域在整个类中

复制
class Outer5{ private int n1 = 100; private static String name = "张三"; //静态内部类 static class Inner{ public void m1(){ //静态内部类访问外部类的静态属性 System.out.println("name = " + name); } } public void f1(){ Inner inner = new Inner(); inner.m1(); } }

外部类访问静态内部类,先创建实例,再访问
静态内部类访问外部类的属性,直接访问,如果存在同名属性,遵守就近原则,如果想要访问外部类的静态属性,可以使用外部类.属性即可
外部其它类访问静态内部类的方式:

复制
//第一种方式 Outer5.Inner inner = new Outer5.Inner(); inner.m1(); System.out.println("======="); //第二种方式,提供一个方法返回实例 Outer5.Inner inner1 = Outer5.getInstanceInner(); inner1.m1();

枚举

自定义枚举类型:

复制
//自定义枚举类型 class Session{ private String name; private String desc; //内部创建所有实例 public static final Session SPRING = new Session("春天","春天的天"); public static final Session SUMMER = new Session("夏天","夏天的天"); public static final Session AUTUMN = new Session("秋天","秋天的天"); public static final Session WINTER = new Session("冬天","冬天的天"); //构造器私有化,防止外部再创建实例 private Session(String name,String desc){ this.name = name; this.desc = desc; } //属性为只读,不能修改,所有只提供属性的get方法 public String getName() { return name; } public String getDesc() { return desc; } @Override public String toString() { return "Session{" + "name='" + name + '\'' + ", desc='" + desc + '\'' + '}'; } }

1.构造器私有化,不能让外部创建实例

2.属性只提供get方法,不能修改属性

3.在内部创建好实例,使用static final修饰

使用enum定义枚举类型

复制
enum Session1{ //定义使用到的常量,使用,分割 SPRING("春天","春天的天"), SUMMER("夏天","夏天的天"), AUTUMN("秋天","秋天的天"), WINTER("冬天","冬天的天"); private String name; private String desc; //构造私有化 private Session1(String name,String desc){ this.name = name; this.desc = desc; } //提供get方法,访问呢属性,不能提供set修改属性 public String getName() { return name; } public String getDesc() { return desc; } @Override public String toString() { return "Session1{" + "name='" + name + '\'' + ", desc='" + desc + '\'' + '}'; } }

1.自定义枚举类型,底层使用final修饰,继承自Enum类
2.自定义枚举对象必须放在枚举类的行首
3.当使用无参函数构造枚举对象的时候,可以省略参数列表和括号
4.使用enum定义的枚举类不能再继承其它类,因为隐式继承了Enum类
5.可以去实现其它接口
使用反汇编执行javap查看源码:

Enum类常用方法

1.name() 返回枚举对象的名字
2.ordinal()返回枚举对象的编号,在定义的时候就确定了,从0开始
3.values()返回所有的枚举对象的数组,可以通过反汇编指令查看源代码发现
4.valueOf(String)将一个字符串转换成枚举对象,这个字符串必须是枚举类定义过的枚举对象
5.compareTo()比较的是两个枚举类型的编号,用当前编号减参数的编号

复制
System.out.println(Session1.SPRING.name()); System.out.println(Session1.SPRING.ordinal()); for(Session1 session1: Session1.values()){ System.out.println(session1); } Session1 Spring = Session1.valueOf("SPRING"); System.out.println(Spring); System.out.println(Session1.SPRING.compareTo(Session1.SUMMER)); /* SPRING 0 Session1{name='春天', desc='春天的天'} Session1{name='夏天', desc='夏天的天'} Session1{name='秋天', desc='秋天的天'} Session1{name='冬天', desc='冬天的天'} Session1{name='春天', desc='春天的天'} -1 */

注解

注解被称为元数据,用于修饰解释包、类、方法、属性、构造器、局部变量等数据信息

和注释一样,注释不影响程序逻辑,但是注解可以被编译和运行,相当于嵌入到代码的补充信息

@interface 不是接口,是注解类,在JDK1.5中加入

修饰注解的注解称为元注解

  • @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
  • @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
  • @SuppressWarnings - 指示编译器去忽略注解中声明的警告。

作用在其他注解的注解(或者说 元注解)是:

  • @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
  • @Documented - 标记这些注解是否包含在用户文档中。
  • @Target - 标记这个注解应该是哪种 Java 成员。
  • @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
posted @   无涯子wyz  阅读(78)  评论(1编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示