内部类(inner)
- 内部类定义
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类(InnerClass)
,类B则称为外部类(OuterClass)
。 - 为什么需要内部类?
具体来说,当一个事物A的内部,还有一个部分需要一个完整的结构B进行描述,而这个内部的完整的结构B又只为外部事物A提供服务,不在其他地方单独使用,那么整个内部的完整结构B最好使用内部类。
总的来说,高内聚、低耦合的面向对象开发原则。
-
举例:
Thread类内部声明了State类,表示线程的生命周期
HashMap类中声明了Node类,表示封装的key和value -
内部类的分类:(参考变量的分类)
成员内部类:直接声明在外部类的里面。
使用static修饰的:静态的成员内部类
不使用static修饰的:非静态的成员内部类**局部内部类:**声明在方法内、构造器内、代码块内的内部类
匿名的局部内部类
非匿名的局部内部类 -
内部类知识:
成员内部类的理解
如何创建成员内部类的实例
如何在成员内部类中调用外部类的结构
局部内部类的基本使用
-
关于成员内部类的理解:
从类的角度看:
- 可以声明属性、方法、构造器、代码块、内部类等结构
- 可以声明父类,
- 可以实现接口
- 可以使用final修饰
- 可以使用abstract修饰
从外部类的成员的角度看:
- 在内部可以调用外部类的结构。比如:属性、方法等
- 可以使用public、缺省权限修饰之外
- 可以使用private、protected修饰
- 可以使用static修饰
举例:
public class OuterClassTest1 {
//说明:局部内部类的使用
public void method1(){
//局部内部类
class A{
//可以声明属性、方法等
}
}
//开发中的场景
public Comparable getInstance(){
//提供了实现了Comparable接口的类
//方式1:提供了接口的实现类的对象
class MyComparable implements Comparable{
@Override
public int compareTo(Object o) {
return 0;
}
}
MyComparable m = new MyComparable();
return m;
//方式2:提供了接口的实现类的匿名对象
class MyComparable implements Comparable{
@Override
public int compareTo(Object o) {
return 0;
}
}
return new MyComparable();
//方式3:提供了接口的匿名实现类的对象
Comparable c = new Comparable(){
@Override
public int compareTo(Object o) {
return 0;
}
};
return c;
//方式4:提供了接口的匿名实现类的匿名对象
return new Comparable(){
@Override
public int compareTo(Object o) {
return 0;
}
};
}
}
- 关于局部内部类的说明:
枚举类(enum)
- 枚举类的理解:
枚举类型本质上也是一种类,只不过是这个类的对象是有限的、固定的几个,不能让用户随意创建。 - 举例:
星期
:Monday(星期一)…Sunday(星期天)性别
:Man(男)、Woman(女)月份
:January(1月)…December(12月)季节
:Spring(春节)…Winter(冬天)三原色
:red(红色)、green(绿色)、blue(蓝色)支付方式
:Cash(现金)、WeChatPay(微信)、Alipay(支付宝)、BankCard(银行卡)、CreditCard(信用卡)就职状态
:Busy(忙碌)、Free(空闲)、Vocation(休假)、Dimission(离职)订单状态
:Nonpayment(未付款)、Paid(已付款)、Fulfilled(已配货)、Delivered(已发货)、Checked(已确认收货)、Return(退货)、Exchange(换货)、Cancel(取消)线程状态
:创建、就绪、运行、阻塞、死亡
- 开发中的建议:
开发中,如果针对于某个类,其实例是确定个数的。则推荐将此类声明为枚举类。
如果枚举类的实例只有一个,则可以看做是单例的实现方式。
- 自定义枚举类
public class SeasonTest {
public static void main(String[] args) {
// Season.SPRING = null;
System.out.println(Season.SPRING);
System.out.println(Season.SUMMER.getSeasonName());
System.out.println(Season.SUMMER.getSeasonDesc());
}
}
//jdk5.0之前定义枚举类的方式
class Season{
//2. 声明当前类的对象的实例变量,使用private final修饰
private final String seasonName;//季节的名称
private final String seasonDesc;//季节的描述
//1. 私有化类的构造器
private Season(String seasonName,String seasonDesc){
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//3. 提供实例变量的get方法
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
//4. 创建当前类的实例,需要使用public static final修饰
public static final Season SPRING = new Season("春天","春暖花开");
public static final Season SUMMER = new Season("夏天","夏日炎炎");
public static final Season AUTUMN = new Season("秋天","秋高气爽");
public static final Season WINTER = new Season("冬天","白雪皑皑");
@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
}
- 使用enum定义枚举类
举例1
enum Season1 implements Info{
//1. 必须在枚举类的开头声明多个对象。对象之间使用,隔开
SPRING("春天","春暖花开"),
SUMMER("夏天","夏日炎炎"),
AUTUMN("秋天","秋高气爽"),
WINTER("冬天","白雪皑皑");
//2. 声明当前类的对象的实例变量,使用private final修饰
private final String seasonName;//季节的名称
private final String seasonDesc;//季节的描述
//3. 私有化类的构造器
private Season1(String seasonName,String seasonDesc){
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//4. 提供实例变量的get方法
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
@Override
public String toString() {
return "Season1{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
@Override
public void show() {
System.out.println("这是一个季节");
}
}
举例2
public class EmployeeTest {
public static void main(String[] args) {
Employee e1 = new Employee("Tom",21,Status.BUSY);
System.out.println(e1);
}
/**
* 定义公司中员工的状态
*
* @author shkstart
* @create 11:18
*/
public enum Status {
BUSY,FREE,VOCATION,DIMISSION;
}
public static class Employee {
private String name;
private int age;
private Status status;
public Employee() {
}
public Employee(String name, int age, Status status) {
this.name = name;
this.age = age;
this.status = status;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", status=" + status +
'}';
}
}
}
- Enum中的常用方法:
6.1 使用enum关键字定义的枚举类,默认其父类是java.lang.Enum类,不要再显示的定义其父类。否则报错。
6.2 熟悉Enum类中常用的方法
String toString(): 默认返回的是常量名(对象名),可以继续手动重写该方法!
(关注)static 枚举类型[] values():返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值,是一个静态方法
(关注)static 枚举类型 valueOf(String name):可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的“名字”。如不是,会有运行时异常:IllegalArgumentException。
String name():得到当前枚举常量的名称。建议优先使用toString()。
int ordinal():返回当前枚举常量的次序号,默认从0开始
public class SeasonTest1 {
public static void main(String[] args) {
// System.out.println(Season1.SPRING.getClass());
// System.out.println(Season1.SPRING.getClass().getSuperclass());
// System.out.println(Season1.SPRING.getClass().getSuperclass().getSuperclass());
//测试方法
//1. toString()
System.out.println(Season1.SPRING);
System.out.println(Season1.AUTUMN);
//2. name()
System.out.println(Season1.SPRING.name());
//3. vlaues()
Season1[] values = Season1.values();
for (int i = 0; i < values.length; i++) {
System.out.println(values[i]);
}
//4. valueOf(String objName):返回当前枚举类中名称为objName的枚举类对象。
//如果枚举类中不存在objName名称的对象,则报错。
String objName = "WINTER";
// objName = "WINTER1";
Season1 season1 = Season1.valueOf(objName);
System.out.println(season1);
//5.ordinal()
System.out.println(Season1.AUTUMN.ordinal());
//通过枚举类的对象调用重写接口中的方法
Season1.SUMMER.show();
}
}
-
枚举类实现接口的操作
情况1:枚举类实现接口,在枚举类中重写接口中的抽象方法。当通过不同的枚举类对象调用此方法时,执行的是同一个方法。System.out.println("Season2.SUMMER.show()"); interface Info1{ void show(); } enum Season2 implements Info1{ SPRING("春天","春暖花开"), SUMMER("夏天","夏日炎炎"), AUTUMN("秋天","秋高气爽"), WINTER("冬天","白雪皑皑"); public void show(){ return "这是一个季节"; } }
情况2:让枚举类的每一个对象重写接口中的抽象方法。当通过不同的枚举类对象调用此方法时,执行的是不同的实现的方法。
interface Info1{
void show();
}
//jdk5.0中使用enum关键字定义枚举类
enum Season2 implements Info1{
//1. 必须在枚举类的开头声明多个对象。对象之间使用,隔开
SPRING("春天","春暖花开"){
public void show(){
System.out.println("春天在哪里?");
}
},
SUMMER("夏天","夏日炎炎"){
public void show(){
System.out.println("宁静的夏天");
}
},
AUTUMN("秋天","秋高气爽"){
public void show(){
System.out.println("秋意浓");
}
},
WINTER("冬天","白雪皑皑"){
public void show(){
System.out.println("大约在冬季");
}
};
注释了解(annotation)
- Annotation的理解
当前阶段 , 相当于保护机制 , 会帮你校验对应的 ,
-
注解的应用场景:
示例1:生成文档相关的注解
示例2:在编译时进行格式检查(JDK内置的三个基本注解)
示例3:跟踪代码依赖性,实现替代配置文件功能 -
Java基础涉及到的三个常用注解
@Override
: 限定重写父类方法,该注解只能用于方法
@Deprecated
: 用于表示所修饰的元素(类,方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择
@SuppressWarnings
: 抑制编译器警告 , 没使用 -
元注解的理解:
元注解:对现有的注解进行解释说明的注解。
讲4个元注解:
(1)@Target:用于描述注解的使用范围
可以通过枚举类型ElementType的10个常量对象来指定
TYPE,METHOD,CONSTRUCTOR,PACKAGE…
(2)@Retention:用于描述注解的生命周期
可以通过枚举类型RetentionPolicy的3个常量对象来指定
SOURCE(源代码)、CLASS(字节码)、RUNTIME(运行时)
唯有RUNTIME阶段才能被反射读取到。
(3)@Documented:表明这个注解应该被 javadoc工具记录。
(4)@Inherited:允许子类继承父类中的注解
拓展: 元数据。
String name = “Tom”;
框架 = 注解 + 反射 + 设计模式 (一般在自定义框架中出现)
包装类
-
为什么要使用包装类?
为了使得基本数据类型的变量具备引用数据类型变量的相关特征(比如:封装性、继承性、多态性),我们给各个基本数据
类型的变量都提供了对应的包装类。 -
(掌握)基本数据类型对应的包装类类型
byte -> Byte
short -> Short
int -> Integer
long -> Long
float -> Float
double ->Double
char -> Character
boolean -> Boolean
-
掌握基本数据类型 与 包装类之间的转换。
3.1 为什么需要转换一方面,在有些场景下,需要使用基本数据类型对应的包装类的对象。此时就需要将基本数据类型的变量转换为
包装类的对象。比如:ArrayList的add(Object obj);Object类的equals(Object obj)
对于包装类来讲,既然我们使用的是对象,那么对象是不能进行+ - * /等运算的。为了能够进行这些运算,就
需要将包装类的对象转换为基本数据类型的变量。3.2 如何转换:
(装箱)基本数据类型 —> 包装类:① 使用包装类的构造器 ② (建议)调用包装类的valueOf(xxx xx)
(拆箱)包装类 —> 基本数据类型:调用包装类的xxxValue()注意:原来使用基本数据类型变量的位置,改成包装类以后,对于成员变量来说,其默认值变化了!
jdk5.0新特性:自动装箱、自动拆箱。
-
String 与 基本数据类型、包装类之间的转换。
基本数据类型、包装类 —> String类型:① 调用String的重载的静态方法valueOf(xxx xx) ; ② 基本数据类型的变量 + “”
String类型 —> 基本数据类型、包装类: 调用包装类的静态方法:parseXxx()