内部类
-
基本介绍
一个类的内部又完整的嵌套了另一个类结构,被嵌套的类称为内部类,嵌套其他类的类称为外部类,是我们类的第五大成员。
内部类的最大特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。(难且重要,底层源码有大量内部类)
-
基本语法
class Outer{ //外部类 class Inner{ //内部类 } } class Other{ //外部其他类 }
-
内部类的分类
- 定义在外部类的局部位置上(比如方法内):
- 局部内部类(有类名)
- 匿名内部类(没有类名,重点)
- 定义在外部类的成员位置上
- 成员内部类(没用static修饰)
- 静态内部类(使用static修饰)
- 定义在外部类的局部位置上(比如方法内):
局部内部类
局部内部类是定义在外部类的局部位置,通常在方法中,并且有类名,本质仍然是一个类
class Outer{
public int a = 1;
private String name = "akak";
public void anony(){
class Inner{
public int a = 1;
private String name = "akak";
}
}
}
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,因为它的地位就是一个局部变量,但是可以使用final修饰,因为局部变量也可以使用final
- 作用域:仅仅在定义它的方法或代码块中
- 局部内部类访问外部类的成员:直接访问
- 外部类在方法中,可以直接创建内部类的对象,然后直接调用方法即可(必须在作用域中)
- 外部其他类不能访问局部内部类
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的常用,使用外部类名.this.成员去访问
匿名内部类
匿名内部类是定义在外部类的局部位置。比如方法中,并且没有类名
- 本质是类
- 内部类
- 该类没有名字
- 同时还是一个对象
-
基本语法
new 类或接口 (参数列表){
类体;
}
//基于接口 interface IA{ public void cry(); } class Outer{ //编译类型IA //运行类型Outer$1 IA tiger = new IA(){ @Override public void cry(){ System.out.println("虎啸"); } }; } //基于类(抽象类) class Father{ public String name; public Father(String name) {//构造器 this.name = name; } public void test() {//方法 } } class Outer2{ //编译类型Father //运行类型Outer2$1 //形参Jack会传递给Father类的构造器 Father fa = new Father("Jack"){ @Override public void test(){ } }; } //还可以将匿名内部类和匿名对象结合 new Father("Jack"){ @Override public void test(){ } }.test(); //直接调用test方法
-
细节
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,因为是一个局部变量
- 匿名内部类只能使用一次,作用域仅仅在定义它的方法或代码块中
- 外部其他类不能访问匿名内部类
- 如果外部类和匿名内部类成员重名时,匿名内部类访问的话,默认遵循就近原则;如果想访问外部类的成员,则可以使用外部类名.this.成员去访问
-
最佳实践
当作实参直接传递,简洁高效
public class Anonymous { public static void main(String[] args) { CellPhone cellPhone = new CellPhone(); cellPhone.alarmclock(new Bell() { @Override public void ring() { System.out.println("起床啦。。。"); } }); cellPhone.alarmclock(new Bell() { @Override public void ring() { System.out.println("迟到了。。。"); } }); } } interface Bell{ void ring(); } class CellPhone { public void alarmclock(Bell bell){ bell.ring(); } } //一个alarmclock方法,可以输出不同的语句 //1. 传递的是实现了 Bell 接口的匿名内部类 //2. 重写了 ring
成员内部类
成员内部类定义在外部类的成员位置,并且没有static修饰
class Outer { public int a = 1; private String name = "akak"; class Inner { int a = 20; private String name = "m4m4"; } public void print(){ Inner in = new Inner(); System.out.println(in.a); } }
-
可以访问外部类的所有成员,包含私有的
-
可以添加任意访问修饰符,因为本质是一个成员
-
作用域和外部类的其他成员一样,为整个类体,整个外部类中都可以使用
-
直接访问外部类的所有成员
-
外部类访问内部类,要先创建成员内部类的对象,再调用属性方法
-
外部其他类也可以访问成员内部类,有2种方法:
-
Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); //先实例化外部类,再实例化内部类 //相当于吧new Inner()当作外部类成员
-
//在外部类中编写一个方法,返回一个内部类对象 class Outer { class Inner { } public Inner getInner(){ return new Inner(); } } Outer outer = new Outer(); Outer.Inner inner = outer.getInner();
-
-
外部类的成员和成员内部类的成员重名的话,遵循就近原则,如果要访问外部类的成员,可以使用外部类名.this.成员去访问
-
静态内部类
静态内部类是定义在外部类的成员位置,并且有static修饰
class Outer {
static class Inner {
}
}
-
可以直接访问外部类的所有静态成员,包含私有的,不能访问非静态成员
-
可以添加任意访问修饰符,因为本质是个成员
-
作用域和其他成员一样,是整个类体
-
静态内部类访问外部类,直接访问(必须是静态的)
-
外部类访问静态内部类需要先创建对象再访问
-
外部其他类访问静态内部类
-
Outer.Inner inner = new Outer.Inner(); //静态内部类可以通过类名去访问,要遵循相应访问权限
//编写方法,返回静态内部类实例 Outer outer = new Outer(); Outer.Inner in = outer.getInner(); class Outer { static class Inner { } public static Inner getInner() { return new Inner(); } }
Outer.Inner inner = Outer.getInner(); //没有创建外部类对象
-
-
如果外部类和静态内部类成员重名的话,采用就近原则,如果想访问外部类的成员,使用外部类名.成员即可(不加this)
小结:
-
内部类
-
局部内部类
-
匿名内部类(重要)
-
成员内部类
-
静态内部类
-
-
匿名内部类使用是重点
-
成员内部类和静态内部类是放在外部类的成员位置,本质就是一个成员
枚举
枚举是一组常量的集合,即枚举属于一种特殊的类,里面只包含一组有限的特定的对象。
枚举的实现方式:
-
自定义枚举
-
构造器私有化,防止直接new
-
去掉set方法,防止属性被修改,可以提高get方法
-
在类内部,直接创建固定的对象
-
优化,可以加入final修饰符,实现底层优化
-
命名通常全部大写,枚举可以有多个属性
-
public class enum1 { public static void main(String[] args) { System.out.println(Season.spring.getDesc()); } } class Season{ private String name; private String desc; private Season(String name, String desc) { this.name = name; this.desc = desc; } public static final Season spring = new Season("spring","warm"); public static final Season summer = new Season("summer","hot"); public static final Season autumn = new Season("autumn","cool"); public static final Season winter = new Season("winter","cold"); public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } }
-
-
enum关键字实现枚举
-
class 换成 enum
-
对象名(实参列表)如SPRING(“春天”,“温暖”)
-
如果有多个常量,使用逗号间隔即可
-
如果使用enum实现枚举,要求将定义的常量对象写在前面
-
public class enum1 { public static void main(String[] args) { System.out.println(Season.SPRING.getDesc()); } } enum Season{ SPRING("spring","warm"),SUMMER("summer","hot"), AUTUMN("autumn","cool"),WINTER("winter","cold"); private String name; private String desc; Season(String name, String desc) { this.name = name; this.desc = desc; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } }
-
-
注意事项
- 使用enum关键字开发一个枚举类时,默认会继承Enum类(javap可以证明)
- SPRING(“spring”,“warm”)要知道调用的哪个构造器
- 如果使用的是无参构造器创建对象,可以省略(),如SPRING;
- 当有多个枚举对象时,使用逗号间隔,最后以分号结尾
- 枚举对象必须放在枚举类的行首
-
enum常用方法
使用enum时会隐式继承Enum类
- toString():不重写就返回对象名,可以重写
- name():输出枚举对象的名称
- ordinal():输出该枚举对象的次序/编号(从0开始)
- values():返回数组,含有定义的所有枚举对象
- valueOf():将字符串转成枚举对象,要求字符串必须为已有的常量名,否则报异常
- compareTo():比较两个枚举常量,比较的就是编号,返回编号之差
-
enum细节
- 使用enum不能继承其他类,因为已经隐式继承Enum类了
- enum实现的枚举类,仍然是一个类,所有可以实现接口
增强for循环,执行流程是依次从nums数组中取出数据,赋给i,取出完毕就结束循环
注解
- 注解也被称为元数据,用于修饰介绍包、类、方法、属性、构造器、局部变量等数据信息
- 和注释不一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息
- 在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替java EE旧版中所遗留的繁冗代码和XML配置等。
基本的Annotation介绍
使用Annotation时要在其前面加@符号,并把该Annotation当成一个修饰符使用。用于修饰它支持的程序元素
三个基本的Annotation:
- @Override:限定某个方法,是重写父类方法,该注解只能用于方法
- @Deprecated:用于表示某个程序元素(类、方法等)已过时
- @SuppressWarnings:抑制编译器警告
-
@Override
只能修饰方法,不能修饰类、属性
不写:还是会重写父类方法
写:检查是否构成重写,构成了就通过,没构成就编译错误
补充说明:
如果发现@interface 表示一个注解类
-
@Deprecated
Deprecated修饰某个元素,表示该元素已过时,即不再推荐使用,但是仍然可以使用,可以修饰方法、类、字段、参数、包等。
@Deprecated的作用可以做到新旧版本的兼容和过渡
-
@SuppressWarnings
当我们不希望看到这些警告时,可以使用SuppressWarnings注解来抑制(不显示)警告信息
@SuppressWarnings({ “all” })
关于@SuppressWarnings的作用范围,和放置的范围相关。在main方法中放置,作用范围就是main方法中
- unchecked是忽略没有检查的警告
- rawtypes是忽略没有指定泛型的警告(传参时没有指定泛型的警告错误)
- unused是忽略没有使用某个变量的警告错误
- @SuppressWarnings可以修饰的程序元素为,查看@Target
- 生成@SuppressWarnings时,不用背,直接点击左侧的黄色提示,就可以选择,注意可以指定生成的位置
元注解(了解)
修饰注解的注解