简介

Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点

Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等

参考资料

IDEA Mac快捷键

函数

简介

  • 函数的概念
    • 函数就是定义在类中的具有特定功能的一段独立小程序
    • 函数也成为方法
    • 通俗的说:函数(方法)是一段可重复调用的代码段
  • 函数分类
    • 普通方法:静态(static)、类方法和实例(对象)方法
    • 构造函数
  • 其它说明:
    • 传参
      • 有参数,则必须传入参数
      • 传参类型要一致
      • 传参个数也要一致,没有则不需要传参
    • 返回值
      • 用关键字return来返回
      • 返回值 void 的方法默认是有一个 return 返回至调用处,一般不写
      • 如果有返回值,return的值要与定义的返回值类型一致
    • 可变参数
      • 可变参数是 jdk1.5 的新特性
      • public static 返回值类型 方法名称(数据类型… 参数名称) 会把传入的数据类型组成一个数组

类方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.tester.ada.function;

/**
* @author ada
* @ClassName FunctionTester
* @Description 类方法
* @Computer Macbook pro
* @Date 2021/12/15 23:41
*/
public class FunctionTester {
public static void main(String[] args) {
getDayInfo(1);
System.out.println("调用返回值:"+getDayInfo(1));
}

/**
* private 修饰符
* static 静态方法、类方法,如果没有就是对象方法就需要 new 对象去调用
* String 声明没有返回值(如果有返回值就用 void,定义返回值类型 return 返回)
* getDayInfo 方法名,遵循小驼峰、动宾短语、动词命名规范
* (int day) 形参(形参类型 形参名,形参类型2 形参名2),如果不需要参数可不定义形参,括号必须要有
*/
private static String getDayInfo(int day) {
switch (day) {
case 1:
case 2:
case 3:
case 4:
case 5:
System.out.println("今天是工作日");
break;
case 6:
case 7:
System.out.println("今天是周末");
break;
default:
System.out.println("非法的数值");
}
return "调用成功";
}
}

类方法示例

对象方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.tester.ada.function;

/**
* @author ada
* @ClassName FunctionTester2
* @Description 对象方法
* @Computer Macbook pro
* @Date 2021/12/15 23:57
*/
public class FunctionTester2 {
public static void main(String[] args) {
// new 对象
FunctionTester2 tester = new FunctionTester2();
int aInt = 3;
double aDouble = 10;
// 对象调用对象方法
System.out.println(tester.sum(aInt,aDouble));
System.out.println(tester.sum(8,12.75));
}
// 定义带有两个参数类型的对象方法
private double sum(int aInt,double aDouble) {
return aInt + aDouble; // 返回没有定义的匿名变量值为 aInt + aDouble
}
}

对象方法示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.tester.ada.function;

/**
* @author ada
* @ClassName FunctionTester3
* @Description 形参和可变参数
* @Computer Macbook pro
* @Date 2021/12/16 21:40
*/
public class FunctionTester3 {
public static void main(String[] args) {
int[] ints = {1, 2, 3, 4};
FunctionTester3 functionTester3 = new FunctionTester3();
System.out.println(functionTester3.plus(ints));
System.out.println(functionTester3.sum(ints));
functionTester3.say("h","e","ll","o");
}

/**
* for 循环
*
* @param ints
* @return
*/
private int plus(int[] ints) {
int sum = 0;
for (int i = 0; i < ints.length; i++) {
sum += ints[i];
}
return sum;
}

/**
* foreach
*
* @param ints
* @return
*/
private int sum(int[] ints) {
int sum1 = 0;
for (int aInt : ints
) {
sum1 += aInt;
}
return sum1;
}

/**
* 可变参数
* @param aStr
*/
private void say(String... aStr) {
String aString = null;
for (String aStr1 : aStr) {
System.out.print(aStr1);
}
}

}

形参和可变参数示例

面向对象

简介

  • Java 是面向对象的语言,在 Java 中,一切皆为对象
  • 每一个人都是一个对象
    • 属性:姓名、性别、年龄、身高、星座
    • 行为:吃饭、睡觉、学习、打豆豆

类与对象

  • 类:共性事务的抽象,是对某一具有共性事物的描述,是概念上的定义
  • 对象:对象是共性事务的一个个体现,是这个类事务的一个个体或者说是类的一个实例(instance)
    • 一个对象是数据和相关方法的集合,数据是对象的状态,方法是对象的行为
    • 面向对象概念构成了 Java 的核心
    • 面向对象具有封装 继承 多态 三大特性
  • 解释:人、手机、水果、苹果是一个类,具体的某个人比如你 比如我是一个具体对象 你的手机 我的手机是一个具体的对象 水果是一个更大的类包含了苹果类可以当成它的父类
  • 总结:① 类是抽象的、很泛的一个概念,对象是某一具体的的事物 ② 类是对象的模板,对象是类的实例
  • 场景:小明 坐着 D553高铁 去拉萨
    • 类:人类、火车类、地理位置类
    • 对象:小明、D553高铁、拉萨
    • 方法、行为:坐着、去

类的创建和实例化

创建类

  • 类的组成:属性+方法
  • 语法声明
1
2
3
4
5
6
7
8
9
10
修饰符  class 类名称{
// 定义属性
修饰符 数据类型 属性; //声明成员变量(属性)
....
// 定义函数 可变参数可用 参数类型... 表示
public 返回值数据类型 方法名称(参数类型 参数名,参数类型 参数名2){
// TODO 程序语句
return 表达式; //返回值 void 可不写
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.tester.ada.target;

/**
* @author ada
* @ClassName MemberTester
* @Description 会员类
* @Computer Macbook pro
* @Date 2021/12/16 23:08
*/
public class MemberTester {
// 一个 P2P 的项目有借款人、有投资人、每个人共有的属性和行为
// 一、数据:共性的数据-->属性(成员变量) 每个会员都有的属性 手机号、密码、用户名、余额
String phone;
String pwd;
String regName;
String amount;

// 二、行为:对象的方法、实例方法(不加 static ) 注册、登录、重置、提现
public String register(String phone, String pwd, String regName) {
if (11 == phone.length() && 6 == pwd.length() && 8 >= regName.length()) {
return "注册成功";
} else {
return "用户信息错误";
}
}

public String login(String phone, String pwd) {
if (11 == phone.length() && 6 == pwd.length()) {
return "Login success";
} else {
return "Login failed";
}
}
}

对象实例化

  • 语法声明

    1
    2
    3
    4
    5
    6
    // 语法一
    类名称 对象名称 = new 类名称();
    // 语法二
    类名称 对象名称 = null; //声明对象
    对象名称 = new 类名称(); //实例化对象
    //有了对象后就可以去设置属性或者调用方法了
  • 访问属性:对象名称.属性名;

  • 为属性赋值:对象名称.属性名 = 值;

  • 访问方法:对象名称.方法名();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.tester.ada.target;

/**
* @author ada
* @ClassName MemberExampleTester
* @Description MemberTester的实例
* @Computer Macbook pro
* @Date 2021/12/16 23:24
*/
public class MemberExampleTester {
public static void main(String[] args) {
// 用户 ada 的手机号是 13555555555 密码是 123456 昵称是 阿达 现在他想要要注册
// 类名 对象名 = new 类名();
MemberTester ada = new MemberTester();
// 设置对象属性
ada.phone = "13555555555";
ada.pwd = "123456";
ada.regName = "阿达";
System.out.println(ada.register(ada.phone, ada.pwd, ada.regName));
}
}

类的创建和实例化

构造函数

概念

  • 构造函数是用构造对象的函数
  • 示例:User user = new User();
  • 构造方法必须与类名一致
  • 使用 new 关键字进行调用
  • 在每个类中都存在一个默认的无参构造方法,默认不显示

分类

  • 构造函数分为两类:带参和无参的构造函数

    • 无参构造函数(默认构造函数)
    1
    2
    3
    4
    //	语法示例
    public 类名称(){
    ...
    }
    • 带参数构造函数
    1
    2
    3
    public 类名称(参数类型 参数名,参数类型 参数名){
    ...
    }
  • 其它说明:

    • 构造函数无返回值,返回的是一个具体的对象
    • 参数类型为 8 大基本数据类型、引用类型
    • 可以重写默认的构造函数(但是这种应该用处不大,一般都是自己重新定义一个带参数的构造函数)
    • 写带参数的构造函数的目的是为了方便创建对象 初始化对象
    • 如果显示的写了构造函数后,还想调用无参的构造函数就必须显示声明一个无参构造函数

注意事项

  • 调用构造函数语法
    • 类名 对象名 = new 类名(); 无参构造函数(默认带有一个,如果写了有参的必须显示声明后才能使用,否则找不到)
    • 类名 对象名 = new 类名(value1,value2); 有参的构造函数
  • 其它注意事项
    • 调用带参构造函数创建对象,可以按照我们的意愿来初始化对象的属性(方便我们初始化对象)
    • 调用无参构造函数:对象属性值对应类型默认值
    • 默认构造函数是自带的(如果没有声明,则编码器会自动补齐)
    • 如果定义了带参构造函数,会覆盖无参构造函数,此时如果需要调用无参构造函数,则必须显示定义无参构造函数

创建

  • this 表示当前对象,也就调用的对象
  • 如果构造函数中不用 this.phone = phone; 而是采用 phone = phone; 由于就近原则两个 phone 都是使用的形参的这样就不起作用,除非把形参的变量名和属性名设置成不同的,不过一般不这样用,每次都要去起两个变量名,阅读性也不高
  • 构造函数中的参数可以添加非属性的其它参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.tester.ada.target;

/**
* @author ada
* @ClassName MemberTester
* @Description 会员类
* @Computer Macbook pro
* @Date 2021/12/16 23:08
*/

public class MemberTester {
// 一个 P2P 的项目有借款人、有投资人、每个人共有的属性和行为
// 一、数据:共性的数据-->属性(成员变量) 每个会员都有的属性 手机号、密码、用户名、余额
String phone;
String pwd;
String regName;
String amount;

//
public MemberTester(String phone, String pwd, String regName, String amount) {
// super(); //Object类先创建出来 构造时会先调用父类的构造函数,这里的 super 可以不写
this.phone = phone;
this.pwd = pwd;
this.regName = regName;
this.amount = amount;
}

// 应为显示声明了带参数的构造函数还想使用无参的就必须要显示声明
public MemberTester() {

}

// 二、行为:对象的方法、实例方法(不加 static ) 注册、登录、重置、提现
public String register(String phone, String pwd, String regName) {
if (11 == phone.length() && 6 == pwd.length() && 8 >= regName.length()) {
return "注册成功";
} else {
return "用户信息错误";
}
}

public String login(String phone, String pwd) {
if (11 == phone.length() && 6 == pwd.length()) {
return "Login success";
} else {
return "Login failed";
}
}
}

调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.tester.ada.target;

/**
* @author ada
* @ClassName MemberExampleTester
* @Description MemberTester的实例
* @Computer Macbook pro
* @Date 2021/12/16 23:24
*/
public class MemberExampleTester {
public static void main(String[] args) {
// 用户 ada 的手机号是 13555555555 密码是 123456 昵称是 阿达 现在他想要要注册
// 类名 对象名 = new 类名();
MemberTester ada = new MemberTester();
// 设置对象属性
ada.phone = "13555555555";
ada.pwd = "123456";
ada.regName = "阿达";
System.out.println(ada.register(ada.phone, ada.pwd, ada.regName));

// 构造函数初始化及调用对象方法
MemberTester link = new MemberTester("13888888888", "666666", "link", "8000");
System.out.println(link.register(link.phone, link.pwd, link.regName));
}
}

调用带参数的构造函数示例

内存分配

分配过程

  • 声明对象:Person per = null; 声明对象时会把 per 对象存在占内存中
  • 实例化对象:per = new Person(); 会给 per 对象开辟一段队内存空间(给对象赋的属性值就会在这块堆内存中,此时还没给对象的属性进行赋值,那么这些属性值都是类型对应的缺省值 如 String–>null int–>0 )
  • 关联:栈内存中的 per 对象会保存一个地址指向堆内存地址的引用 如 0x1354464548

内存分配过程说明

存放分类

  • 栈内存
    • 基本类型变量(基本数据类型 四类八种)
    • 对象引用,应用类型名称(比如上面的 per),即队堆的引用地址
  • 堆内存
    • new 创建的对象和数组
    • 属性
  • 全局数据区(静态区)
    • static 属性
  • 全局代码区
    • 方法
  • 字符串池(常量池)
    • jdk1.7 前在方法区,1.7 后再堆中间
    • 共享的 String 对象

内存地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.tester.ada.target;

/**
* @author ada
* @ClassName MemoryTester
* @Description 内存分配(堆栈)
* @Computer Macbook pro
* @Date 2021/12/18 00:02
*/
public class MemoryTester {

public static void main(String[] args) {
String str1 = "hello"; //在字符串池(常量池)中创建了一个字面值为 hello
String str2 = "hello"; //字符串池(常量池)中 已经有一个字面值为 hello 的了,那么直接用 str2 指向这个地址
String str3 = new String("hello"); // new 给 str3 分配一块栈内存执行一个堆内存地址 0x156164646
String str4 = new String("hello"); // new 给 str4 分配另一块栈内存执行一个堆内存地址 0x6484684
System.out.println(str1 == str2); //结果为 true 应为 str1 和 str2 指向的是同一个常量池中的地址
System.out.println(str2 == str3); //结果为 false 指向的不同地址,只能说字面值相等, == 比较的是内存地址
System.out.println(str3 == str4); //结果为 false 指向的不同地址(如果地址相同肯定值也相同了)
System.out.println("---------------重新分配地址---------------");
str3 = str1; //把 str1 的地址分配给 str3
str4 = str2; //把 str2 的地址分配给 str4
System.out.println(str3 == str4); //因为 str2 也是指向 str1 的地址所以 str3 和 str4 最终都是指向的 str1 的地址,因此为 true
System.out.println("---------------此时 str3 和 str4 的内存没有人引用了会成为垃圾内存,会被 gc 回收---------------");

}

}

内存地址分配示例图

内存地址分配详解图

包装类

简介

  • 数据类型分类:基本数据类型和引用数据类型
  • 矛盾:基本数据类型不是类(类都是大写),因此 Java 为了调和矛盾引入了包装类
  • 解决矛盾:8 个基本数据类型对应 8 个包装类
类型 基本数据类型 包装类
整型 byte Byte
~ short Short
~ int Interger
~ long Long
浮点型 float Float
~ double Double
字符型 char Character
布尔型 boolean Boolean
  • 包装类:以类的形式来管理基本数据类型
    • 如 Integer 使用类的形式表示整数
    • Integer i = new Integer(20);

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.tester.ada.packages;

/**
* @author ada
* @ClassName PackageClassTester
* @Description 包装类
* @Computer Macbook pro
* @Date 2021/12/18 13:25
*/
public class PackageClassTester {
public static void main(String[] args) {
// 整型-->Integer-->描述整型数据类型的类
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MIN_VALUE);

// 包装类语法
Integer aInteger = new Integer(10);
System.out.println(aInteger);

// 装箱(基本数据类型变成包装类)
Integer Integer = new Integer(20); //手动装箱
Double aDouble = new Double(20.5);

// 自动装箱(直接把一个 int 类型的数值用 Integer 包装类接收) 自动装箱 自动拆箱是 jdk1.5 后提供的新特性
Integer Integer2 = 30;

// 拆箱(包装类变成基本数据类型)
int aInt = Integer.intValue(); //手动拆箱,调用 数据类型Value() 方法
double adouble = aDouble.doubleValue();
System.out.println(aInt);
System.out.println(adouble);

// 自动拆箱 Integer 是上面手动装箱的变量,然后用对应的基本类型接收
int bInt = Integer;

}
}

包装类示例

包装类常用方法

xxxValue()
  • 以基本数据类型返回指定的数值—>(拆箱)
    • int j = i.intValue();
获得最大最小值
  • 获得最大值:Integer.MAX_VALUE
  • 获得最小值:Integer.MIN_VALUE
将字符串转换为基本数据类型
  • 如果字符串不是数字格式会出现格式异常
1
2
3
4
String str = "10086";
int i = Integer.parseInt(str);
double d = Double。parseDouble(str);
String str2 = String.parseString(i);

转换

示例一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.tester.ada.conversion;

/**
* @author ada
* @ClassName TypeConversionTester
* @Description 类型转换
* @Computer Macbook pro
* @Date 2021/12/19 23:37
*/
public class TypeConversionTester {
public static void main(String[] args) {
int i = 10;
double doubleValue = 20;
double d = i; //低位到高位自动转换,测试经理是测试从业人员
int j = (int) doubleValue; //高位到低位强制转换,测试从业人员不一定是测试经理
System.out.println("d的值为:" + d + ",j的值为:" + j);
}
}

转换示例

示例二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.tester.ada.conversion;

/**
* @author ada
* @ClassName MemberTester
* @Description 会员类
* @Computer Macbook pro
* @Date 2021/12/19 23:53
*/
public class MemberTester {
InvestTester tom = new InvestTester();
BorrowerTester jack = new BorrowerTester();
MemberTester tom1 = tom; // 投资人自动向上转型为会员类
MemberTester jack1 = jack; //借款人自动向上转型为会员类

MemberTester link = new MemberTester();
MemberTester ada = new MemberTester();

InvestTester link1 = (InvestTester) link; //大类型强制转换为小类型
BorrowerTester ada1 = (BorrowerTester) ada; //大类型强制转换为小类型

InvestTester tom3 = new InvestTester();
BorrowerTester tom4 = (BorrowerTester) tom3; // 无法将投资人转换为借款人

}
1
2
3
4
5
6
7
8
9
10
11
package com.tester.ada.conversion;

/**
* @author ada
* @ClassName InvestTester
* @Description 投资人也是会员,继承会员类
* @Computer Macbook pro
* @Date 2021/12/19 23:53
*/
public class InvestTester extends MemberTester {
}
1
2
3
4
5
6
7
8
9
10
11
package com.tester.ada.conversion;

/**
* @author ada
* @ClassName BorrowerTester
* @Description 借款人也是会员,继承会员类
* @Computer Macbook pro
* @Date 2021/12/19 23:55
*/
public class BorrowerTester extends MemberTester{
}

转换示例二

Java 三大特性

封装

概念

  • 封装是 Java 三大特性之一,把对象的内部细节封闭起来,只提供操作对象属性的公共方法(把属性设置为 private,然后提供公共公开的 set get 方法)
  • 封装是面向对象编程语言对客观世界的模拟 例如,电视机它的内部元件就是被封闭起来了,仅仅暴露电视机按钮供人们使用,这样就没有人能任意更改咱们的元件
  • Java 里面通过将属性设置成私有的,对属性都使用暴露出来的公共接口去操作,这样数据才更安全,更好维护

目的

  • 通过公开方法访问数据,可以从方法里加入逻辑控制,避免不合理的访问,可进行数据检查,保证数据完整性,防止不希望的交互和非法的访问便于后期修改,提高代码的可维护性

实现

  • 属性私有化:隐藏对象的属性和实现细节,不允许外部直接访问(设置为 private,这样就不能通过 对象.属性名 调用)
  • 提供公开的方法操作和访问属性(set get)
  • get set 只针对属性,如果不需要进行逻辑处理可引入 lombok 后在类名前添加 @Data 注解隐式声明,针对与需要做逻辑处理的显示声明,编写逻辑处理代码
  • boolean 类型的属性生成的 get set 方法中 set 会变为 is
  • pom.xml引入 lombok 依赖后,在类名前添加 @Data 注解
1
2
3
4
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

示例

1
2
3
4
5
6
7
<!--    依赖  -->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.tester.ada.trait.encapsulation;

import lombok.Data;

/**
* @author ada
* @ClassName MemberTester
* @Description 封装
* @Computer Macbook pro
* @Date 2021/12/20 22:37
*/
@Data
public class MemberTester {

private String phone;
private String password;

public void setPhone(String phone) {
if (11 == phone.length())
this.phone = phone;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.tester.ada.trait.encapsulation;

/**
* @author ada
* @ClassName BorrowerTester
* @Description 调用公共公开方法
* @Computer Macbook pro
* @Date 2021/12/20 22:42
*/
public class BorrowerTester extends MemberTester {
public static void main(String[] args) {
BorrowerTester link = new BorrowerTester();
link.setPhone("13888888888");
System.out.println(link.getPhone());
}
}

封装示例

继承

简介

  • 继承是 Java 三大特性的另一大特性,继承是从已有的类中派生出新的类,新的类能吸收已有类的属性和行为,并能扩展新的能力
  • 一个类 A 继承 B 可以通过 extends 来实现(extends 翻译为扩展,我们通俗的称为继承)
  • 一个不由任何类派生出来的类称为基类(派生类) ,一个派生类(子类)最近的上层类称为该类的父类,从某一个派生类出来的类称为该类的子类
  • 派生类(子类)与父类之间是一个子与父的关系,子跟父之间的关系是 is a 的关系,父类和子类是 has a 的关系
    • 水果类 –>热带水果、亚热带水果 –>芒果、香蕉、火龙果(热带水果)
    • 芒果 extends 热带水果 –> 子类 extends 父类 –> 子类 is a 父类 –> 芒果 is a 热带水果 = 热带水果 has a 芒果
  • Java 中子类不能获得父类的构造方法

语法

1
2
3
修饰符 class SubClass extends SuperClass{
//类定义
}

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.tester.ada.trait.inherit;

import lombok.Data;

/**
* @author ada
* @ClassName MemberTester
* @Description 会员类(父类)
* @Computer Macbook pro
* @Date 2021/12/20 23:38
*/
@Data
public class MemberTester {
private String phone;
private String pwd;
private String regName;
private double amount;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.tester.ada.trait.inherit;

import lombok.Data;

/**
* @author ada
* @ClassName BorrowerTester
* @Description 借款人继承会员类(子类)
* @Computer Macbook pro
* @Date 2021/12/20 23:37
*/
@Data
public class BorrowerTester extends MemberTester{
// 子类继承父类,但是子类有自己的一些属性 比如借款人需要关注你是否有车 是否有房

private boolean hasCar;
private boolean hasHouse;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.tester.ada.trait.inherit;

import lombok.Data;

/**
* @author ada
* @ClassName InvestTester
* @Description 投资人继承会员类(子类)
* @Computer Macbook pro
* @Date 2021/12/20 23:38
*/
@Data
public class InvestTester extends MemberTester{
// 只有投资人才会去投资,因此要单独给它写一个方法,子类自己扩展的方法
public void invest(double doubleValue){
System.out.println("调用:InvestTester.invest()"+"投资【"+doubleValue+"】元成功");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.tester.ada.trait.inherit;

/**
* @author ada
* @ClassName Tester1
* @Description 测试
* @Computer Macbook pro
* @Date 2021/12/21 00:31
*/
public class Tester1 {
public static void main(String[] args) {
InvestTester ada = new InvestTester();
ada.setAmount(10000);
System.out.println(ada.getAmount()); // set get方法来自于父类
ada.invest(3000); //调用子类扩展的方法

BorrowerTester dream = new BorrowerTester();
dream.setPhone("13555555555"); //调用父类的 set 方法
dream.setHasCar(true); // 调用子类扩展的方法
System.out.println(dream.getPhone());
System.out.println(dream.isHasCar());
}
}

继承示例

多态

概念

  • 不同的对象对应相同的方法表现出不同的特征和响应:如对于自行车和汽车他们都定义了刹车的方法,但是它们的刹车方式却完全不同,又比如动物类都有吃东西的方法,食肉动物吃东西的方法是吃肉食,食草动物吃东西的方法是吃草 蔬菜,乐器都会发出声音,不同乐器演奏出来的表现形式各不相同
  • 父类类型来接受子类的对象,Java 通过方法重写来实现多态
  • 通过方法重写,子类可以实现父类的某些方法,使其具有自己的特征 (例如都是人类,别人实现一个小目标是一个亿,我们的一个小目标是换个手机,因此要重写“富人”和“穷人”实现目标的方法,使其具有自己的特征)
  • 通过方法重写 相同的对象(变量),执行同一个方法表现出不同的行为特征,就称为多态
  • 多态的优点:提高代码的复用性,简化代码

缘由

  • 在很对时候会使用父类类型接受子类对象,但是父类类型又没有实现该方法,会出现报错,如下图所示
  • 当然可以直接在父类中实现该方法解决报错,不过很多时候子类有自己的实现方式,比如充值的方法,针对于投资人是充值投资,针对于借款人是充值还款,因此要在子类中实现自己的充值方法

多态报错

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.tester.ada.trait.Polymorphism;

import lombok.Data;

/**
* @author ada
* @ClassName MemberTester
* @Description 多态
* @Computer Macbook pro
* @Date 2021/12/21 01:44
*/
@Data
public class MemberTester {
private String phone;
private String pwd;
private String regName;
private double amount;

//投资和借款人如测试人员,VIP 客户,系统内部人员充值享有 1.5 倍翻倍
public void recharge(double doubleValue) {
if (doubleValue < 100 || doubleValue > 500000) {
System.out.println("MemberTester.recharge():" + "充值失败,金额必须大于等于 100 或小于等于 50万");
} else {
this.amount += doubleValue * 1.5;
System.out.println("MemberTester.recharge():" + "尊贵的客户恭喜您获得 1.5 倍翻倍机会,当前累计充值【" + this.getAmount() + "】成功,感谢您的使用");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.tester.ada.trait.Polymorphism;

/**
* @author ada
* @ClassName BorrowerTester
* @Description 多态
* @Computer Macbook pro
* @Date 2021/12/21 01:54
*/
public class BorrowerTester extends MemberTester {
//借款人还款
public void recharge(double doubleValue) {
if (doubleValue < 100 || doubleValue > 500000) {
System.out.println("BorrowerTester.recharge():" + "充值失败,金额必须大于等于 100 或小于等于 50万");
} else {
this.setAmount(this.getAmount() + doubleValue);
System.out.println("BorrowerTester.recharge():" + "还款【" + doubleValue + "】成功,累计还款" + this.getAmount() + "元,您的信誉保持良好可继续申请借贷");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.tester.ada.trait.Polymorphism;

/**
* @author ada
* @ClassName InvestTester
* @Description 多态
* @Computer Macbook pro
* @Date 2021/12/21 01:53
*/
public class InvestTester extends MemberTester {
//投资人充值投资
public void recharge(double doubleValue) {
if (doubleValue < 100 || doubleValue > 500000) {
System.out.println("InvestTester.recharge():" + "充值失败,金额必须大于等于 100 或小于等于 50万");
} else {
this.setAmount(this.getAmount() + doubleValue);
System.out.println("InvestTester.recharge():" + "充值【" + doubleValue + "】成功,累计充值" + this.getAmount() + "元,您可以去投资赚钱收益了");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.tester.ada.trait.Polymorphism;

/**
* @author ada
* @ClassName Tester1
* @Description 不同对象调用实现多态
* @Computer Macbook pro
* @Date 2021/12/21 01:44
*/
public class Tester1 {
public static void main(String[] args) {
MemberTester link = new MemberTester();
link.recharge(1000); //其它会员充值(非投资和借款人如测试人员,VIP 客户,系统内部人员)
link.recharge(2000); //其它会员充值(非投资和借款人如测试人员,VIP 客户,系统内部人员)

MemberTester ada = new InvestTester();
ada.recharge(100); //先投资 100 试下水
ada.recharge(1000); //感觉回款还可以,再多投点试下

MemberTester dream = new BorrowerTester();
dream.recharge(1000); //手上暂时只有 1000 先还了再说
dream.recharge(5000); //发工资了再还 5000

### HashSet

+ `无序` `不可重复`
+ 支持的数据类型为引用类型(类、数组)(如果添加基本数据类型会自动装箱)



```java
package com.tester.ada.common.gather.HashSet;

import java.util.HashSet;

/**
* @author ada
* @ClassName HashSetTester
* @Description HashSet 无序、不可重复
* @Computer Macbook pro
* @Date 2021/12/26 14:05
*/
public class HashSetTester {
public static void main(String[] args) {
HashSet<String> set = new HashSet<String>();
set.add("ada");
set.add("ada"); // 由于不可重复,这里相同的值就覆盖了,因此 size 不变
set.add("link");
set.add("dream");
System.out.println(set.size()); //获取集合大小
System.out.println(set.contains("link")); //判断是否包含 link
System.out.println(set.isEmpty()); //判断是否为空
// set.clear(); 清空
Object[] objs = set.toArray(); // 将集合转换成对应数据类型的数组(这里用的父类类型接收)
for (Object obj : objs) {
System.out.println(obj);
}
}
}

HashSet示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.tester.ada.common.gather.HashSet;

import java.util.HashSet;
import java.util.Iterator;

/**
* @author ada
* @ClassName HashSetTester1
* @Description 遍历HashSet
* @Computer Macbook pro
* @Date 2021/12/26 14:27
*/
public class HashSetTester1 {
public static void main(String[] args) {
HashSet<String> nations = new HashSet<String>();
nations.add("china");
nations.add("USA");
nations.add("Japan");
System.out.println("===============forEach===============");
for (String nation : nations) {
System.out.println(nation);
}
System.out.println("===============迭代器一===============");
for (Iterator nation1 = nations.iterator(); nation1.hasNext(); ) {
System.out.println(nation1.next());
}
System.out.println("===============迭代器二===============");
Iterator nation2 = nations.iterator();
while (nation2.hasNext()) {
System.out.println(nation2.next());
}
}
}

HashSet遍历

示例二

  • 其实示例一种虽然实现了多态,但是并没有发挥出多态的优点:提高代码的复用性,简化代码
  • 也就是说这里的 recharge() 方法写了三遍实现,但是业务逻辑几乎一致(这里不考虑 1.5 倍翻倍了),因此需要优化代码示例如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.tester.ada.trait.Polymorphism;

import lombok.Data;

/**
* @ClassName MemberTester1
* @Description 多态简化代码
* @Author ada
* @Computer Mac mini
* @Date 2021/12/22 18:12
*/
@Data
public class MemberTester1 {
private String phone;
private String pwd;
private String regName;
private double amount;

public boolean recharge(double doubleValue) {
if (doubleValue < 100 || doubleValue > 500000) {
System.out.println("MemberTester.recharge():" + "充值失败,金额必须大于等于 100 或小于等于 50万");
return false;
} else {
this.setAmount(this.getAmount() + doubleValue);
return true;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.tester.ada.trait.Polymorphism;

/**
* @ClassName InvestTester1
* @Description TODO
* @Author ada
* @Computer Mac mini
* @Date 2021/12/22 18:18
*/
public class InvestTester1 extends MemberTester1{
@Override
public boolean recharge(double doubleValue) {
boolean flag = super.recharge(doubleValue);
if (flag){
System.out.println("InvestTester1.recharge():" + "充值【" + doubleValue + "】成功,累计充值" + this.getAmount() + "元,您可以去投资赚钱收益了");
}
return flag;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.tester.ada.trait.Polymorphism;

/**
* @ClassName BorrowerTester1
* @Description TODO
* @Author ada
* @Computer Mac mini
* @Date 2021/12/22 18:29
*/
public class BorrowerTester1 extends MemberTester1 {
@Override
public boolean recharge(double doubleValue) {
boolean flag = super.recharge(doubleValue);
if (flag) {
System.out.println("BorrowerTester1.recharge():" + "还款【" + doubleValue + "】成功,累计还款" + this.getAmount() + "元,您的信誉保持良好可继续申请借贷");
}
return flag;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.tester.ada.trait.Polymorphism;

/**
* @ClassName Tester2
* @Description TODO
* @Author ada
* @Computer Mac mini
* @Date 2021/12/22 18:31
*/
public class Tester2 {

public static void main(String[] args) {
MemberTester1 link = new MemberTester1();
link.recharge(1000); //其它会员充值(非投资和借款人如测试人员,VIP 客户,系统内部人员)
link.recharge(2000); //其它会员充值(非投资和借款人如测试人员,VIP 客户,系统内部人员)

MemberTester1 ada = new InvestTester1();
ada.recharge(100); //先投资 100 试下水
ada.recharge(1000); //感觉回款还可以,再多投点试下

MemberTester1 dream = new BorrowerTester1();
dream.recharge(1000); //手上暂时只有 1000 先还了再说
dream.recharge(5000); //发工资了再还 5000
}
}

多态示例二

常用

String API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.tester.ada.common.string;

import java.nio.charset.StandardCharsets;

/**
* @author ada
* @ClassName StringTester
* @Description String 类常用 API
* @Computer Macbook pro
* @Date 2021/12/22 21:25
*/
public class StringTester {
public static void main(String[] args) {
String str = new String("hello"); // new 给 str 分配
// 判断是以指定字符串开头或结尾
System.out.println(str.startsWith("hel"));
System.out.println(str.endsWith("o"));
// 字符创截取
System.out.println(str.substring(1)); //下标从 0 开始
System.out.println(str.substring(2, 3)); //包前不包后
// 字符串拆分
String str1 = "ada,link,test";
String[] str2 = str1.split(","); //以逗号进行分割
for (String str3 : str2) {
System.out.print(str3 + "\t");
}
System.out.println();
// 字符串查找 indexOf lastIndexOf
System.out.println(str1.indexOf("a")); //第一个 a 所在的位置 0
System.out.println(str1.lastIndexOf("a")); //最后一个 a 所在的位置 2
// 判断字符串 str 变量是否包含 llo
System.out.println(str.contains("llo"));
// 比较 str 变量和 hello 字面值是否相等,大小写敏感
System.out.println(str.equals("Hello"));
// 比较 str 变量和 hello 字面值是否相等,大小写不敏感
System.out.println(str.equalsIgnoreCase("HELlo"));
// compareTo、compareToIgnoreCase 比较两个字符串 ASC 码差值 如果相等返回 0,左边比右边小返回负数 左比右大返回正数
System.out.println("a".compareToIgnoreCase("c")); // --> -2
// 字符串拼接
System.out.println("he".concat("llo")); // --> hello
// isEmpty 判断字符串是否为空 length() 为 0 时返回 true
System.out.println("".isEmpty()); // -->空字符串 这里返回 true
// trim 去掉左右空格
System.out.println(" ada ".trim());
// 获取字符串长度
System.out.println("link".length());
// toCharArray 将字符串转换为字符数组 然后获取下标为 0 的
System.out.println("adaTester".toCharArray()[0]);
// charAt 返回字符串指定位置的值,返回值为 char 类型 参数不能为负数,由于下标从 0 开始最大值为 长度-1
System.out.println(str.charAt(str.length() - 1));
// getBytes 得到一个操作系统默认的编码格式的字节数组 byte[]
System.out.println(new String("中国".getBytes(StandardCharsets.UTF_8)));
// 大小写转换
System.out.println("aDA".toUpperCase()); // 转换为大写 --> ADA
System.out.println("aDA".toLowerCase()); // 转换为小写 --> ada
// 替换replace没有用到正则 First All 有用到正则 如果匹配 .的话需要用 \\. 进行转义
System.out.println("ada".replace("a", "c")); // 把所有的 a 替换成 c --> cdc
System.out.println("ada".replaceFirst("a", "b")); // 把第一个 a 替换成 b --> bda
System.out.println("ada".replaceAll("a", "b")); // 把所有的 a 替换成 c --> cdc
// 字符串描述 String 的类方法 用类名调用 valueOf
System.out.println(String.valueOf("hello ada"));

}
}

常量

  • 对于一些固定不变的属性可通过 public static final 修饰为常量
  • 加了static 后只能在 static 方法中访问
  • final 属性不可修改 常量不能生成 set 方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.tester.ada.common.constant;

/**
* @author ada
* @ClassName FinalTester
* @Description 设置常量
* @Computer Macbook pro
* @Date 2021/12/22 22:55
*/

public class FinalTester {
// 常量用大写命名
private static final String COUNTRY = "中国";
public static final String LOCATION = "Earth";

public static void main(String[] args) {
// 本类中可以访问
System.out.println(FinalTester.COUNTRY);
// COUNTRY = "final不可修改";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.tester.ada.common.constant;

/**
* @author ada
* @ClassName Tester
* @Description 访问常量
* @Computer Macbook pro
* @Date 2021/12/22 22:59
*/
public class Tester {
public static void main(String[] args) {
// 其它类无法访问 private 的常量
// System.out.println(FinalTester.COUNTRY);
// 访问时用类名.常量名
System.out.println(FinalTester.LOCATION);
}
}

常量示例

集合类

简介

  • Java 的集合类是特别有用的工具类
  • 可以存储多个对象(保存的数据类型需要是引用数据类型)
  • 常见的有: ArrayList、HashSet、HashMap

ArrayList

  • ArrayList 可变数组,数组列表,有序 可重复
  • 如果是一维数组是需要声明长度的,也就是固定长度,有时候并不满足要求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.tester.ada.common.gather.ArrayList;

import java.util.ArrayList;

/**
* @author ada
* @ClassName ArrayListTester
* @Description ArrayListTester可变数组,数组列表
* @Computer Macbook pro
* @Date 2021/12/23 21:49
*/
public class ArrayListTester {
public static void main(String[] args) {
String[] names = new String[40];
names[0] = "ada";
names[1] = "link";
names[39] = "Shadow";
// 假设现在已经 40 个同学了,那么再来一个同学,String的数组就放不下了,因为固定开辟的长度是 40,因此可以用 ArrayList
ArrayList<String> arrayList = new ArrayList<String>(); // 指定泛型为 String 类型
arrayList.add("ada");
arrayList.add("link");
arrayList.add("Shadow");
System.out.println(arrayList.get(1)); // get方法获取下标1的值--> link
arrayList.forEach(name -> System.out.println(name)); // foreach Lambda 表达式
arrayList.remove(1); //remove 移除下标为 1 的数据-->link 就会被删除,Shadow 下标从 2 变为 1
System.out.println(arrayList.get(1)); // get方法获取下标1的值--> Shadow
System.out.println(arrayList.size()); // 获取集合的大小 --> 2 (上面移除了一个)
System.out.println(arrayList.isEmpty()); // 判断对象是否为空 --> false
System.out.println(arrayList.contains("link")); // 判断对象是否包含了一个数据 link --> false
arrayList.set(1, "dream"); // 替换下标 1 的值为dream(修改)
System.out.println(arrayList.get(1)); // 输出-->dream
}

ArrayList示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.tester.ada.common.gather.ArrayList;

import java.util.ArrayList;
import java.util.Iterator;

/**
* @author ada
* @ClassName ArrayListTester1
* @Description ArrayList 遍历
* @Computer Macbook pro
* @Date 2021/12/23 22:37
*/
public class ArrayListTester1 {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(1);
arrayList.add(3);
arrayList.add(5);

System.out.println("---------------foreach---------------");
for (Integer number : arrayList) {
System.out.println(number);
}

System.out.println("---------------普通for循环---------------");
for (int i = 0; i < arrayList.size(); i++) {
System.out.println(arrayList.get(i));
}

System.out.println("---------------Lambda表达式一---------------");
arrayList.forEach(number -> {
System.out.println(number); //写执行的逻辑
});

System.out.println("---------------Lambda表达式二---------------");
arrayList.forEach(System.out::println);

System.out.println("---------------迭代器---------------");
// 迭代器 hasNext-->如果有下一个元素就为 true next->得到下一个元素,并且会自动去进行移动,类似 i++改变循环条件
for (Iterator iterator = arrayList.iterator(); iterator.hasNext(); ) {
Integer ints = (Integer) iterator.next();
System.out.println(ints);
}
}
}

ArrayList遍历

HashSet

  • 无序 不可重复
  • 支持的数据类型为引用类型(类、数组)(如果添加基本数据类型会自动装箱)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.tester.ada.common.gather.HashSet;

import java.util.HashSet;

/**
* @author ada
* @ClassName HashSetTester
* @Description HashSet 无序、不可重复
* @Computer Macbook pro
* @Date 2021/12/26 14:05
*/
public class HashSetTester {
public static void main(String[] args) {
HashSet<String> set = new HashSet<String>();
set.add("ada");
set.add("ada"); // 由于不可重复,这里相同的值就覆盖了,因此 size 不变
set.add("link");
set.add("dream");
System.out.println(set.size()); //获取集合大小
System.out.println(set.contains("link")); //判断是否包含 link
System.out.println(set.isEmpty()); //判断是否为空
// set.clear(); 清空
Object[] objs = set.toArray(); // 将集合转换成对应数据类型的数组(这里用的父类类型接收)
for (Object obj : objs) {
System.out.println(obj);
}
}
}

HashSet示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.tester.ada.common.gather.HashSet;

import java.util.HashSet;
import java.util.Iterator;

/**
* @author ada
* @ClassName HashSetTester1
* @Description 遍历HashSet
* @Computer Macbook pro
* @Date 2021/12/26 14:27
*/
public class HashSetTester1 {
public static void main(String[] args) {
HashSet<String> nations = new HashSet<String>();
nations.add("china");
nations.add("USA");
nations.add("Japan");
System.out.println("===============forEach===============");
for (String nation : nations) {
System.out.println(nation);
}
System.out.println("===============迭代器一===============");
for (Iterator nation1 = nations.iterator(); nation1.hasNext(); ) {
System.out.println(nation1.next());
}
System.out.println("===============迭代器二===============");
Iterator nation2 = nations.iterator();
while (nation2.hasNext()) {
System.out.println(nation2.next());
}
}
}

HashSet遍历

HashMap

  • 以键值对的形式来保存数据
  • 键不可以重复,重复时,后者键值覆盖前者
  • 键和值支持的数据类型为引用类型
  • Map 可以描述任何一个对象信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.tester.ada.common.gather.HashMap;

import java.util.Collection;
import java.util.HashMap;
import java.util.Set;

/**
* @author ada
* @ClassName HashMapTester
* @Description HashMap 键值存储,键不可重复
* @Computer Macbook pro
* @Date 2021/12/26 15:11
*/
public class HashMapTester {
public static void main(String[] args) {
HashMap<String, Object> info = new HashMap<String, Object>();
info.put("name", "ada");
info.put("age", 18);
info.put("age", 25); // key 相同 覆盖前面的
info.put("Profession", "测试工程师");
System.out.println(info.get("age")); // 输出 --> 25(如果 key 不存在,则为 null)
info.remove("name"); // 移除 key 为 name 的
System.out.println(info.size()); //获取大小 --> 2
System.out.println(info.containsKey("name")); // key 中,是否有一个值是 name --> false (上面已经移除了)
System.out.println(info.containsValue("工程师")); // value 中是否有一个值是 工程师 --> false(要完全匹配)

Set<String> allKey = info.keySet(); // 获取所有的 key 返回的是一个 Set 集合对象 需要循环遍历
System.out.println(allKey);
Collection<Object> allValues = info.values(); // 获取所有的值 返回一个 Collection 集合对象
System.out.println(allValues);
info.keySet().forEach(key -> System.out.println(key + "-->" + info.get(key))); //循环输出
}
}

HashMap示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.tester.ada.common.gather.HashMap;

import java.util.HashMap;

/**
* @author ada
* @ClassName HashMapTester1
* @Description HashMap 遍历
* @Computer Macbook pro
* @Date 2021/12/26 15:44
*/
public class HashMapTester1 {
public static void main(String[] args) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("name", "ada");
map.put("age", 25);
map.put("Profession", "测试工程师");
System.out.println("===============forEach===============");
for (String key : map.keySet()) {
System.out.println(key + "--->" + map.get(key));
}
System.out.println("===============Lambda 表达式===============");
map.forEach((key, value) -> {
System.out.println(key + "=" + value);
});
}
}

HashMap遍历

Json

简介

  • JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式
  • 对象表示为键值对
  • 数据由逗号分割
  • 花括号保存对象
1
2
3
4
5
6
{
"name": "ada",
"age": "25",
"gender": "男",
"Profession": "测试工程师"
}
  • 方括号保存数组
1
2
3
4
5
[
{ "name": "ada", "age": "25","gender": "男","Profession": "测试工程师"},
{ "name": "ada1", "age": "26","gender": "男","Profession": "测试工程师1"},
{ "name": "ada2", "age": "27","gender": "男","Profession": "测试工程师2"}
]
  • Json 可以描述任何一个对象信息

生成实体类

  • 除了手写还可以通过一些插件(GsonFormatPlus)快速生成实体类(在插件中搜索安装)
  • 创建实体类,在类中右键–>生成–>GsonFormatPlus–>粘贴 json 格式文本(GsonFormatPlus中可设置成 Lombok PS:pom.xml 需要先引入)

设置成Lombok

生成实体

  • @NoArgsConstructor 生成一个无参的构造函数
  • @Data 生成 get set 方法

转换

  • 采用第三方工具 fastJson 或 gson(这里以 fastJson 为例)
  • fastJson 需要在 pom 中引入
1
2
3
4
5
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
  • 将Json字符串转对象 JSONObject.parse()
  • 将Json数组格式字符串转对象 JSONObject.parseArray()
  • 将对象转换为字符串

json 字符串转 Map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.tester.ada.common.json;

import com.alibaba.fastjson.JSONObject;

import java.util.Map;

/**
* @author ada
* @ClassName Json2Map
* @Description Json 转 Map
* @Computer Macbook pro
* @Date 2021/12/26 18:20
*/
public class Json2Map {
public static String strJson = "{\n" +
" \"name\": \"ada\",\n" +
" \"age\": \"25\",\n" +
" \"gender\": \"男\",\n" +
" \"Profession\": \"测试工程师\"\n" +
"}";

public static void main(String[] args) {
// strJson Json 格式的文本
Map map = (Map)JSONObject.parse(strJson);
System.out.println(map); // 这里会直接调用 map.toString()
}
}

Json转Map示例

Json 字符串转对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.tester.ada.common.json;

import lombok.Data;
import lombok.NoArgsConstructor;

/**
* @author ada
* @ClassName User
* @Description User 实体
* @Computer Macbook pro
* @Date 2021/12/26 18:06
*/
@NoArgsConstructor
@Data
public class User {

private String name;
private String age;
private String gender;
private String profession;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.tester.ada.common.json;

import com.alibaba.fastjson.JSONObject;

/**
* @author ada
* @ClassName Json2Object
* @Description Json 转 对象
* @Computer Macbook pro
* @Date 2021/12/26 19:03
*/
public class Json2Object {

public static void main(String[] args) {
/**
* Json2Map.strJson json 格式的文本
* User.class 需要转换的类的字节码对象 类名.class
*/
User users = JSONObject.parseObject(Json2Map.strJson, User.class);
System.out.println(users); //调用users.toString() 因为加了@Data 注解 重写了 toString 方法不然输出就是父类的
System.out.println(users.getName()); //获取对象的属性
}
}

Json转对象示例

Maven

简介

  • Maven 中央仓库 Maven 这个项目维护了一个网站,在这个上面维护了非常多开源的 jar 包,并且维护了每个 jar 包的版本便于开发者们去下载使用
  • Maven:解决协同合作时版本问题 协同合作时传输问题
  • Maven 是一个项目管理工具,它包含了一个项目对象模型(Project Object Model)–> pom.xml
  • 作用:项目构建(编译 打包 发布 测试 等等)
  • 目前大部分企业在在做项目(Java)时的首选项目构建管理工具(部分较老的企业也有用 Ant,Android 一般采用gradle
  • IDE 一般都自带有 Maven,如果没有集成开发环境需要自行下载安装配置环境变量(不管哪种方式使用,做好都修改下镜像源为国内源,本地仓库地址设置为非系统盘–>修改 settings.xml 文件 mirrors localRepository
  • Maven 添加依赖时的流程(比如我们 pom.xml 文件中添加了 fastjson 的依赖配置)
    • 查看本地仓库是否有指定的 fastjson 的 jar 包
    • 如果有直接引入,如果没有自动从远程仓库搜索 fastjson 的 jar 包(如果远程仓库找不到就会报错,有可能版本不对,或者网络原因,或者在私服,或者自己打的 jar包)
    • 建立 Maven 项目时将从本地资源获得 Maven 的本地资源库依赖资源
    • 如果没找到,则从默认的 Maven(或者自己配置)的远程仓库查找下载
  • POM
    • pom(Project Object Model)即项目对象模型,是 Maven 工作的基本单位
    • 位于项目目录中的 xml 文件:pom.xml
    • pom.xml其中可以包含项目构建的各种配置信息
    • 每个项目只有一个
  • Maven 的特点
    • 可以使用 Maven 来编译你的代码
    • 项目打包也可以使用 Maven 来完成
    • Maven 可以实现模块化管理
    • Maven 可以在线管理依赖,项目依赖也很方便获取
    • Maven 提供了一些丰富的插件,方便项目持续集成

新建 Maven 工程参数

  • groupId:分组,一般填写组织机构,如 com.incar
  • artifactId:项目包名(项目打包成 jar 包的 ID,或者说 jar 包名字)
  • version:版本
  • name: Maven工程名称
  • packaging:打包方式 (jar war pom)我用的 pom
  • <relativePath>../pom.xml</relativePath>:继承父类的依赖(如果是多个子模块都需要用到的依赖,可以在父模块引用依赖子模块添加该标签即可)
1
2
3
4
5
6
<groupId>com.adalucky</groupId>
<artifactId>automation</artifactId>
<version>V1.0.0</version>
<name>endpoint</name>
<packaging>pom</packaging>
<description>Demo project for Spring Boot</description>

Maven 项目结构

  • src/main/java:一般是开发人员写代码的目录
  • src/main/resource:开发人员放项目资源的目录
  • src/test/java:放单元测试或测试人员写代码的目录
  • src/main/resource:放测试资源的目录
  • Maven Dependencies:通过 Maven 下载下来的项目依赖包存放的目录
  • target:存放构建后文件的目录

文件解析

properties解析

  • Properties 类是 java.util 提供的工具类
  • 当前类名.class.getResourceAsStream 当前类读取一个文件,并且转换为输入流
  • 文件路径的更路径是/src/main/resources (可在 idea 的配置文件中修改)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.tester.ada.Parsing.properties;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
* @ClassName PropertiesTester
* @Description 解析properties配置文件
* @Author ada
* @Computer Mac mini
* @Date 2021/12/29 15:19
*/
public class PropertiesTester {
private static Properties properties = new Properties();

public static void main(String[] args) {
// java提供解析properties配置文件的类
//加载资源文件作为一个输入流: 当前类名.class.getResourceAsStream("从当前路径的/src/main/resources根路径开始写文件路径")
InputStream in = PropertiesTester.class.getResourceAsStream("/config/user.properties");

try {
properties.load(in); // properties对象加载这个流,有可能文件地址不对导致流对象为空
} catch (IOException e) {
e.printStackTrace();
}

System.out.println(properties.getProperty("name")); // getProperty 是 Properties类的对象方法
System.out.println(properties.getProperty("age"));
System.out.println(properties.getProperty("gradle"));
System.out.println(properties.getProperty("flag"));
System.out.println(properties.getProperty("profession"));
}

/**
* getProperty方法的封装
*
* @param key 传入的键
* @return 返回键的值
*/
public static String get(String key) {
return properties.getProperty(key);
}

/**
* 获取整型数据
*
* @param key 传入的键
* @return 返回键的值
*/
public static Integer getInteger(String key) {
String value = get(key);
return null == value ? null : Integer.valueOf(value);
}

/**
* 获取 Boolean 型数据
*
* @param key 传入的键
* @return 返回键的值
*/
public static Boolean getBoolean(String key) {
String value = get(key);
return null == value ? null : Boolean.valueOf(value);
}

}

properties解析示例

Xml 解析

简介

  • XML:( Extensible Markup Language ) 可扩展的标记语言,类似于 html 都是标记语言(可以写逻辑处理的叫编程语言 比如 js py等等)
  • 特点
    • 可扩展性,在遵循 xml 语法的前提下支持自定义和修改
    • 标记语言,具有结构性,意味着也是类似于 html 中的标签来定义文档
    • xml 在姓名中的使用更多的是作为数据载体 而出现的,xml 和 json 都是一种数据交互格式
    • 非常适合万维网数据 传输,提供统一方法描述和交换结构化数据
  • xml 与 html 的区别:xml 是作为数据传输的工具,是一种数据载体, html 是数据展示的工具(展示成一个网页)

文档结构

  • xml 的文档结构跟 HTML 类似,也是一种树形结构,从上往下发展
  • 父、子以及同胞等术语用于描述元素之间的关系
    • 父元素拥有子元素
    • 相同层级上的子元素称为同胞(兄弟或姐妹)
  • 所有的元素都可以有文本内容和属性(类似 html)

语法

  • xml 声明语法:元素的属性值,必须要用双引号 “ “引起来 注释使用 <!-- 注释内容 -->
1
<?xml version="1.0" encoding="utf-8"?>
  • 根元素:

    • xml 必须包含根元素,它是所有其它元素的父元素,比如一下实例中 person 就是根元素
    1
    2
    3
    4
    5
    <person>
    <name>ada</name>
    <age>25</age>
    <gender></gender>
    </person>
    • 所有元素标签成对出现
    • 大小写敏感
    • 嵌套使用(注意嵌套顺序)

dom4j 解析技术

dom4j : Document Object Model for Java

  • 添加依赖:dom4j
1
2
3
4
5
6
 <!-- dom4j,解析 xml 文件的库 -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>${dom4j.version}</version>
</dependency>
  • 创建解析器 SaxReader 对象
  • 获取document 对象
  • 获取根元素
  • 获取根元素下的子元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8" ?>
<!--标签必须要用根元素-->
<Users>
<user_1 cid="1">
<name>John</name>
<email>john@example.com</email>
<age>18</age>
</user_1>

<user_2 cid="2">
<name>ada</name>
<email>ada@example.com</email>
<age>22</age>
</user_2>

<user_3 cid="3">
<name>link</name>
<email>link@example.com</email>
<age>31</age>
</user_3>
</Users>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.tester.ada.Parsing.xml.entity;

import lombok.Data;

/**
* @author ada
* @ClassName User
* @Description User 实体类
* @Computer Macbook pro
* @Date 2021/12/29 21:20
*/
@Data
public class User {
private String cid;
private String name;
private String email;
private String age;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.tester.ada.Parsing.xml;

import com.tester.ada.Parsing.xml.entity.User;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.util.ArrayList;
import java.util.List;

/**
* @ClassName XMLTester
* @Description 解析 xml 文件工具
* @Author ada
* @Computer Mac mini
* @Date 2021/12/29 18:57
*/
public class XMLTester {
private static Document document;
private static List<User> users = new ArrayList<User>(); //创建 List 保存每一个 User 对象


public static void main(String[] args) {
readXml("/config/user.xml").forEach(user -> System.out.println(user));

}

/**
* 解析 xml 工具类
*
* @param xmlPath xml 路径
* @return 所有对象 List 集合
*/
public static List<User> readXml(String xmlPath) {
// 创建 SAXReader对象 --> dom4j的依赖引入的
SAXReader reader = new SAXReader();
try {
// 读取一个 xml 文件 --> 成为一个 Document 对象
document = reader.read(XMLTester.class.getResourceAsStream(xmlPath));
} catch (DocumentException e) {
e.printStackTrace();
}
// 读取根元素对象
Element rootElement = document.getRootElement();
// System.out.println(rootElement.getName());
// 读取根节点下所有的子节点对象(根节点相当一级菜单,然后获取二级菜单),返回一个 list 列表
List<Element> elements = rootElement.elements();
// element为遍历出的每一个子节点
elements.forEach(element -> {
User user = new User(); //创建 User 对象用 set 方法对实体赋值
String elementName = element.getName(); //子节点标签名
String idAttr = element.attribute("cid").getValue(); // 子节点 ID 属性
// System.out.println(elementName+"-------->id:"+idAttr);
user.setCid(idAttr);
List<Element> userInfoElements = element.elements(); //子节点的子节点对象
userInfoElements.forEach(userInfoElement -> {
String tagName = userInfoElement.getName();//标签名
String tagValue = userInfoElement.getStringValue(); //标签中的文本
// System.out.println(tagName+"-------->"+tagValue);
if ("name".equals(tagName)) {
user.setName(tagValue);
} else if ("age".equals(tagName)) {
user.setAge(tagValue);
} else if ("email".equals(tagName)) {
user.setEmail(tagValue);
} else if ("cid".equals(tagName)) {
user.setCid(tagValue);
}
});
users.add(user);
});
return users;
}
}

解析示例

反射

  • 在上面的 xml 解析时如果每次在 xml 的子节点中新增了标签,那么就需要再去添加一个 if else 做判断,不好维护,因此可通过反射技术实现通用性处理
  • 反射 –> 运行时编程 –> 通用性处理

概念

  • Java 反射机制是在运行状态中对任意一个类都能够知道这个类的所有属性和方法
  • 对于任意一个对象都能够调用它的任意一个方法和属性
  • 这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制

本质

  • 根据类的自己吗 class 文件获取一个类的细节,包括构建出来,通过对象去调用方法、操作属性
  • 关键字:反射 反向获取 映射
  • Java 中每一个类都有一个 class 对象,可以通过这个 class 对象获取它对应的属性和方法,然后再用这个对象的类去调用获取的方法
  • 在 Java 中 Class 可以用来描述所有的类 Method 可以描述所有的方法

反射的实现

  • 获取类的字节码对象
1
Class<User> clazz = Class.forName("com.tester.ada.Parsing.entity.User");
  • 通过字节码去创建对象
1
User user= clazz.newInstance();
  • 通过字节码获取到可以调用到的方法
1
2
String methodName = "set"+(name.chaeAt(0)+"").toUpperCase()+name.substring(1);
Method method = clazz.getMethod(methodName,String.class);
  • 调用 method
1
method.invoke(user,value);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.tester.ada.Parsing.Mapping;

import com.tester.ada.Parsing.xml.entity.User;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
* @ClassName MappingTest
* @Description 反射类的实现
* @Author ada
* @Computer Mac mini
* @Date 2022/1/5 16:51
* @JDKVersion JDK1.8
*/
public class MappingTest {
public static void demo() {
try {
Class<User> clazz = (Class<User>) Class.forName("com.tester.ada.Parsing.xml.entity.User");
User user = clazz.newInstance(); //创建类的对象
String methodName = "set" + "Name"; //拼接方法名
Method method = clazz.getMethod(methodName, String.class); //映射这个 set 方法
method.invoke(user, "调用反射设值"); //用创建的对象(user)调用(invoke)上面映射的方法(method),传入的值为 String类型的 【调用反射设值】
System.out.println(user.getName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
MappingTest.demo();
}
}

反射实现示例

获取 Class 对象

  • Class 类:用于描述类的一个类(属性、方法、构造器)
  • Class 对象
    • 封装了所有对应的类的细节信息
    • 将class 文件读入内存,则会创建一个 Class 对象
    • Class 对象是 jvm 自动化创建的,一个类只产生一个 Class 对象
    • 运行时编程
  • 获得 Class 对象(获取 Test类的 Class)
    • 通过对象调用 getClass 方法,例创建 test 对象:test.getClass();
    • 通过类名去获取:Test.class;
    • 通过类路径注册获取:Class.forName(“com.tester.ada.Parsing.xml.entity.User”);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.tester.ada.Parsing.Mapping;

/**
* @ClassName MappingTest2
* @Description 获得 Class 对象的三种方式
* @Author ada
* @Computer Mac mini
* @Date 2022/1/5 17:47
* @JDKVersion JDK1.8
*/
public class MappingTest2 {
public static void demo() {
// 方式一:通过对象调用 getClass 方法获取Class
Test test = new Test();
Class clazz1 = test.getClass();
// 方式二:通过类名去获取:Test.class;
Class clazz2 = Test.class;
// 方式三:通过类路径`注册`获取
Class clazz3 = null;
try {
clazz3 = Class.forName("com.tester.ada.Parsing.Mapping.Test");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(clazz1 == clazz2); //Class 对象是 jvm 自动化创建的,一个类只产生一个 Class 对象,因此这里 1 2 3 都是指向的同一个地址
System.out.println(clazz2 == clazz3);
}

public static void main(String[] args) {
MappingTest2.demo();
}
}

获取类的Class对象

获取类名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.tester.ada.Parsing.Mapping;

/**
* @ClassName MappingTest3
* @Description 类相关属性获取
* @Author ada
* @Computer Mac mini
* @Date 2022/1/5 18:05
* @JDKVersion JDK1.8
*/
public class MappingTest3 extends MappingTest {
public static void demo() {
Class clazz = MappingTest3.class;
// 获取当前类的类名,包括了路径
System.out.println("当前类名【" + clazz.getName() + "】"); //-->当前类名【com.tester.ada.Parsing.Mapping.MappingTest3】
// 获取当前类的包名
System.out.println("当前类的包名【" + clazz.getPackage().getName() + "】"); //-->当前类的包名【com.tester.ada.Parsing.Mapping】
// 判断是都为接口
System.out.println("是否为接口【" + clazz.isInterface() + "】"); //-->是否为接口【false】
// 获取父类的类名
System.out.println("父类类名【" + clazz.getSuperclass().getName() + "】"); //-->父类类名【com.tester.ada.Parsing.Mapping.MappingTest】
}

public static void main(String[] args) {
MappingTest3.demo();
}
}

获取类名示例

获取字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.tester.ada.Parsing.Mapping;

import java.lang.reflect.Field;
import java.util.Arrays;

/**
* @ClassName MappingTest4
* @Description 获取字段
* @Author ada
* @Computer Mac mini
* @Date 2022/1/5 18:47
* @JDKVersion JDK1.8
*/
public class MappingTest4 {
public static void demo() {
Class clazz = Test.class;
// 获取 public 字段 -->例:public字段:public java.lang.String com.tester.ada.Parsing.Mapping.Test.name
Field[] publicFields = clazz.getFields();
Arrays.asList(publicFields).forEach(field -> System.out.println("public字段:" + field));
// 获取所有字段 -->例:所有字段:private java.lang.Integer com.tester.ada.Parsing.Mapping.Test.age
Field[] allFields = clazz.getDeclaredFields();
Arrays.asList(allFields).forEach(field -> System.out.println("所有字段:" + field));
// 获取字段的信息:名字+类型+修饰符(public 1,private 2) -->例:字段名:age 字段类型:class java.lang.Integer 修饰符:2
Arrays.asList(allFields).forEach(field -> System.out.println("字段名:" + field.getName() + "\t字段类型:" + field.getType() + "\t修饰符:" + field.getModifiers()));
// 根据字符获取 Class 对象字段
try {
Field field = clazz.getField("code");
System.out.println("+++++++++++++++++++++++获取指定字符串的属性+++++++++++++++++++++++");
System.out.println("字段名:" + field.getName() + "\t字段类型:" + field.getType() + "\t修饰符:" + field.getModifiers());
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
demo();
}
}

获取字段

获取方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.tester.ada.Parsing.Mapping;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
* @author ada
* @ClassName MappingTest5
* @Description 获取方法
* @Computer Macbook pro
* @Date 2022/1/5 21:14
* @JDKVersion JDK1.8
*/
public class MappingTest5 {
public static void demo() {
Class clazz = Test.class;
// 获取当前类的所有 public 方法 示例-->public static java.lang.String com.tester.ada.Parsing.Mapping.Test.demo1()
Method[] methods = clazz.getMethods();
Arrays.asList(methods).forEach(method -> System.out.println("1.获取的是类public方法:" + method));
// 获取的是类自身声明的所有方法,包含public、protected和private方法
Method[] allMethod = clazz.getDeclaredMethods();
Arrays.asList(allMethod).forEach(method -> System.out.println("2.获取的是类自身声明的所有方法:" + method));
// 获取指定方法的 无参数时填 null 或者不填 clazz.getDeclaredMethod 和 getMethods()一样只有范围不一样
// 一个是本类 一个还包含父类或者实现的接口,如果方法的修饰符为protected 请用, getDeclaredMethod 方法,为 public 请用 getMethod 方法
try {
Method demo1Method = clazz.getDeclaredMethod("demo1", String.class, Integer.class);
System.out.println("3.方法的修饰符:" + demo1Method.getModifiers() +
"\t方法的名称:" + demo1Method.getName() +
"\t方法的返回值类型:" + demo1Method.getReturnType() +
"\t方法的参数个数:" + demo1Method.getParameterCount() +
"\t方法的参数类型:" + Arrays.asList(demo1Method.getParameterTypes()).toString());
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// Method[] getMethods() 获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法。
Method[] publicMethod = clazz.getMethods();
Arrays.asList(publicMethod).forEach(method -> System.out.println("4.获取的是类和继承实现的public方法:" + method));
}

public static void main(String[] args) {
demo();
}
}

方法的调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.tester.ada.Parsing.Mapping;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
* @author ada
* @ClassName MappingTest6
* @Description 方法的调用
* @Computer Macbook pro
* @Date 2022/1/5 22:09
* @JDKVersion JDK1.8
*/
public class MappingTest6 {
public static void demo() {
Class clazz = Test.class;
try {
Method method = clazz.getMethod("demo4"); //方法没有参数,可以不传参数类型或者传 null
System.out.println("静态方法用 null 调用:" + method.invoke(null));
System.out.println("静态方法用对象调用:" + method.invoke(clazz.newInstance()));
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
demo();
}
}

调用静态方法示例

获取构造函数及创建对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.tester.ada.Parsing.Mapping;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;

/**
* @author ada
* @ClassName MappingTest7
* @Description 获取构造函数及创建对象
* @Computer Macbook pro
* @Date 2022/1/5 22:30
* @JDKVersion JDK1.8
*/
public class MappingTest7 {
public static void demo() {
Class clazz = Test.class;
// 获取当前类所有 public 构造函数 -->例:public com.tester.ada.Parsing.Mapping.Test()
Constructor[] publicConstructors = clazz.getConstructors();
// getDeclaredConstructors 获取所有构造函数包括继承、实现、非 public
// Constructor[] constructors = clazz.getDeclaredConstructors();
Arrays.asList(publicConstructors).forEach(constructor -> System.out.println(constructor));
// 获取对应参数类型的构造函数 传入参数类型
try {
Constructor testConstructors = clazz.getConstructor(String.class, Integer.class, Integer.class);
System.out.println("三个参数构造函数初始化对象:" + testConstructors.newInstance("str", 15, 20)); //初始化对象
System.out.println("构造函数名称:" + testConstructors.getName());
System.out.println("构造函数参数列表:" + Arrays.asList(testConstructors.getParameterTypes()).toString());
System.out.println("构造函数参数个数:" + testConstructors.getParameterTypes().length);
System.out.println("构造函数修饰符:" + testConstructors.getModifiers());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
// 获取无参的构造函数 参数类型可以传 null 或者不传
try {
Constructor tester = clazz.getConstructor(null);
System.out.println("无参构造函数初始化对象:" + tester.newInstance()); //初始化对象
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
demo();
}
}

创建对象的两种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.tester.ada.Parsing.Mapping;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
* @author ada
* @ClassName MappingTest8
* @Description 创建对象
* @Computer Macbook pro
* @Date 2022/1/5 23:09
* @JDKVersion JDK1.8
*/
public class MappingTest8 {
public static void demo() {
// Class创建对象
Class clazz = Test.class;
try {
Object obj = clazz.newInstance();
System.out.println(obj);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
// 构造器创建对象
try {
Constructor c = clazz.getConstructor(String.class, Integer.class, Integer.class);
System.out.println(c.newInstance("a", 20, 35));
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
demo();
}
}

Excel 解析

  • 采用阿里巴巴的开源工具类 easyExcel
  • 引入依赖 lombok easyexcel
1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>${easyexcel.version}</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package com.tester.ada.Parsing.excel.service;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.support.ExcelTypeEnum;

import java.util.Map;

/**
* @author ada
* @ClassName Dome
* @Description demo演示
* @Computer Macbook pro
* @Date 2022/1/6 22:58
* @JDKVersion JDK1.8
*/
public class Dome {
public static void demo() {
// 创建 ExcelReaderBuilder 实例
ExcelReaderBuilder readerBuilder = EasyExcel.read();
// 读取文件对象
readerBuilder.file("ada/src/main/resources/excel/easyExcel.xlsx");
// 指定 sheet(可以传下标或者工作表名)
readerBuilder.sheet(0);
// 自动关闭输入流
readerBuilder.autoCloseStream(true);
// 设置文件格式 根据文件的后缀进行设置
readerBuilder.excelType(ExcelTypeEnum.XLSX);
// 注册监听器使用观察者模式进行数据的解析(一行一行读取封装成一个对象称为观察者模式)
readerBuilder.registerReadListener(new AnalysisEventListener() {
// 需要传入ReadListener对象,但是它又是一个接口,所以用 new AnalysisEventListener() 匿名内部类实现抽象方法
@Override
public void invoke(Object o, AnalysisContext analysisContext) {
// 把每次读取的数据封装到 Object o(这是一个多态的应用,实际上是LinkedHashMap类型 ),然后回调 invoke 回调函数
System.out.println(o);
}

@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// 数据读取完毕后进行的一些操作(自动调用)
System.out.println("数据读取完毕");
}
});
// 构建读取器,上面的都是做一些读取的配置相关
ExcelReader reader = readerBuilder.build();
// 读取所有
reader.readAll();
// 读取完毕
reader.finish();
}

/**
* 指定监听器类型
* 监听器默认是LinkedHashMap类型 我们指定为 Map 类型
*/
public static void demo1() {
// 创建 ExcelReaderBuilder 实例
ExcelReaderBuilder readerBuilder = EasyExcel.read();
// 读取文件对象
readerBuilder.file("ada/src/main/resources/excel/easyExcel.xlsx");
// 指定 sheet(可以传下标或者工作表名),不指定会默认读取所有的 sheet
readerBuilder.sheet(0);
// 自动关闭输入流
readerBuilder.autoCloseStream(true);
// 设置文件格式 根据文件的后缀进行设置
readerBuilder.excelType(ExcelTypeEnum.XLSX);
// 注册监听器使用观察者模式进行数据的解析(一行一行读取封装成一个对象称为观察者模式)
readerBuilder.registerReadListener(new AnalysisEventListener<Map<Integer, String>>() {
// 需要传入ReadListener对象,但是它又是一个接口,所以用 new AnalysisEventListener() 匿名内部类实现抽象方法

@Override
public void invoke(Map<Integer, String> integerStringMap, AnalysisContext analysisContext) {
// 将默认的 Object类型(实际上是LinkedHashMap类型)指定为 Map<Integer, String> 类型
integerStringMap.forEach((k, v) -> {
System.out.print(k + ":" + v + "\t");
});
System.out.println("");
}

@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// 数据读取完毕后进行的一些操作(自动调用)
System.out.println("数据读取完毕");
}
});
// 构建读取器,上面的都是做一些读取的配置相关
ExcelReader reader = readerBuilder.build();
// 读取所有
reader.readAll();
// 读取完毕
reader.finish();
}

public static void main(String[] args) {
demo1();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.tester.ada.Parsing.excel.service;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
* @author ada
* @ClassName DomePro
* @Description 简化代码
* @Computer Macbook pro
* @Date 2022/1/6 23:39
* @JDKVersion JDK1.8
*/
public class DomePro {
public static void demo() {
List<Map<Integer, String>> dataList = new LinkedList<Map<Integer, String>>();
EasyExcel.read("ada/src/main/resources/excel/easyExcel.xlsx")
.sheet()
.registerReadListener(new AnalysisEventListener<Map<Integer, String>>() {
@Override
public void invoke(Map<Integer, String> integerStringMap, AnalysisContext analysisContext) {
dataList.add(integerStringMap);
dataList.forEach(maps -> {
maps.forEach((k, v) -> System.out.print(k + ":" + v + "\t"));
System.out.println("");
});
}

@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("读取完毕");
}
}).doRead();
}

public static void main(String[] args) {
demo();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.tester.ada.Parsing.excel.entity;

/**
* @author ada
* @ClassName ExecelData
* @Description excel 抽象类,所有的实体类需要继承该类
* @Computer Macbook pro
* @Date 2022/1/7 00:25
* @JDKVersion JDK1.8
*/
public abstract class ExecelData {
// 抽象类,所有的Excel实体类都需要继承该类,使用@ExcelProperty注解完成实体类和Excel字段的映射
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.tester.ada.Parsing.excel.entity;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

import java.util.Date;

/**
* @author ada
* @ClassName EasyExcelEntity
* @Description 实体类,映射成指定对象
* @Computer Macbook pro
* @Date 2022/1/7 00:10
* @JDKVersion JDK1.8
*/
@Data
public class EasyExcelEntity extends ExecelData {
// @ExcelProperty 注解将表头和实体类映射
@ExcelProperty("ID")
private String id;
@ExcelProperty("用户名")
private String name;
@ExcelProperty("邮箱")
private String email;
@ExcelProperty("性别")
private String gander;
@ExcelProperty("积分")
private Integer score;
@ExcelProperty("IP")
private String IP;
@ExcelProperty("登录次数")
private Integer count;
@ExcelProperty("加入时间")
private Date date;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package com.tester.ada.Parsing.excel.service;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import org.apache.poi.ss.formula.functions.T;

import java.util.LinkedList;
import java.util.List;

/**
* @author ada
* @ClassName easyExcelService
* @Description 读写 excel 服务
* @Computer Macbook pro
* @Date 2022/1/6 22:58
* @JDKVersion JDK1.8
*/
public class easyExcelService {
/**
* @param Source_Path 源路径
* @param sheetIndex 表单索引
* @param clazz 实体类(必须要继承 ExcelData)
* @param <T> 统一指定泛型
* @return 返回实体类对象 list 集合
*/
public static <T> List<T> readExcel(String Source_Path, Integer sheetIndex, Class<T> clazz) {
if (isExcel(Source_Path)) {
List<T> readList = new LinkedList<>();
EasyExcel.read(Source_Path)
.head(clazz) //设置要反射的类为传入的类
.sheet(sheetIndex)
.registerReadListener(new AnalysisEventListener<T>() {
@Override
public void invoke(T data, AnalysisContext analysisContext) {
readList.add(data);
}

@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("读取完毕");
}
}).doRead();
return readList;
}
return null;
}

/**
* @param target_Path 回写的路径
* @param Sheet_name 回写时候工作表命名
* @param execelDataList 回写的数据
* @param clazz 回写的表头对应的实体类
*/
public static void writeExcel(String target_Path, String Sheet_name, List<T> execelDataList, Class clazz) {
ExcelWriterBuilder head = EasyExcel.write(target_Path)
// 回写的格式按照.head传入的实体类格式进行写入,避免没有表头
.head(clazz);
if (isExcel(target_Path)) {
head.excelType(ExcelTypeEnum.XLS);
} else {
head.excelType(ExcelTypeEnum.XLSX);
}
head.sheet(Sheet_name)
.doWrite(execelDataList);
System.out.println("数据已回写至【" + target_Path + "】");
}

/**
* 根据传入的文件名称最后一个逗号取后缀判断是否是Excel文件
*
* @param Source_Path 传入的文件路径(必须以xls||xlsx结尾)
* @return 返回 boolean 值
*/
public static boolean isExcel(String Source_Path) {
String strType = Source_Path.substring(Source_Path.lastIndexOf("."));
if (".xls".equalsIgnoreCase(strType) || ".xlsx".equalsIgnoreCase(strType)) {
return true;
} else {
System.err.println("文件格式不是【xls、xlsx】格式");
// 0,正常退出,1异常退出,不会进入return false;
System.exit(0);
}
return false;
}

/* public static void main(String[] args) {
List list = readExcel("ada/src/main/resources/excel/easyExcel.xlsx", 0, EasyExcelEntity.class);
System.out.println(list.get(0));
writeExcel("/Users/ada/Desktop/easyExcel2.xlsx","第一页",list,EasyExcelEntity.class);
}*/
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.tester.ada.Parsing.excel.controlle;

import com.tester.ada.Parsing.excel.entity.EasyExcelEntity;
import com.tester.ada.Parsing.excel.service.easyExcelService;
import org.apache.poi.ss.formula.functions.T;

import java.util.List;

/**
* @author ada
* @ClassName ExcelControlle
* @Description excel 读写接口
* @Computer Macbook pro
* @Date 2022/1/7 01:20
* @JDKVersion JDK1.8
*/
public class ExcelControlle {
/**
* @param Source_Path 需要读取Excel文件的全路径xxx.xls/xlsx
* @param sheetIndex Excel文件中的Sheet的索引,从 0 开始
* @param clazz Excel需要映射的实体类,该类必须要实现ExecelData接口
* @return
*/
public static <T> List<T> read(String Source_Path, Integer sheetIndex, Class<T> clazz) {
return easyExcelService.readExcel(Source_Path, sheetIndex, clazz);
}

/**
* @param target_Path 回写的目标路径
* @param Sheet_name 回写的表名称
* @param execelDataList 回写的数据List<>类型
* @param clazz 回写时候该实体类进行格式输出(这个类继承一下ExecelData)
*/
public static void write(String target_Path, String Sheet_name, List<T> execelDataList, Class clazz) {
easyExcelService.writeExcel(target_Path, Sheet_name, execelDataList, clazz);
}

public static void main(String[] args) {
List list = read("ada/src/main/resources/excel/easyExcel.xlsx", 0, EasyExcelEntity.class);
System.out.println(list.get(0));
write("/Users/ada/Desktop/easyExcel3.xlsx", "第一页", list, EasyExcelEntity.class);
}
}

异常

简介

  • 异常:代码在运行过程中出现的非正常情况
  • 异常处理:在程序出现异常时仍然可以正确执行完

异常机制

  • 判断一门变成语言是都成熟的标准
  • 可以让异常处理代码和正常业务逻辑分离,保证程序健壮性、容错性、优雅性
  • 缺点是影响代码的可读性

抛出异常

  • 方式一:在方法名后 throws 抛出异常的类型
  • 方式二:在方法名后 throws 抛出 Exception 异常(父类异常,所有的异常都继承该类)

try…catch

补充知识

JRE

为什么需要安装 jdk

  • jdk 提供了编译器
  • jdk 提供了 java 运行环境(jre)
  • jre 下有很多现成的 jar包,这些 jar 包构成了 Java SE 的一个基本框架,实现了基本的服务

jre 下 jar 包的调用

  • jre 下的类
    • java.lang 下面的包不需要导包
    • 其它类需要 import 导包
  • 自己写的类
    • 同一个 package 直接使用,无需显示导入
    • 其它package 下需要 import 导包
  • 其它项目工程
    • 导出 jar 包–>提供开发套件 SDK
    • 将 jar 包添加到私服/项目构建

重载重写

方法的重载

  • 同一个类中函数名相同,参数类型或个数不同
    • 参数的个数不一样
    • 参数的类型不一样(包括顺序)

方法的重写

  • 方法的重写也称为方法的覆写
  • 出现继承中,子类重写父类的方法,实现多态(子类定义了和父类同名的方法)
  • 注意:被重写的方法修饰符(访问权限)不能比父类更严格

修饰符

访问修饰符

  • 将程序开发人员按角色区分可分为设计者与调用者
  • 一个人可能同时又是设计者和调用者
  • 修饰符的出现是为了控制设计者设计的类有哪些东西可以被调用者使用,哪些东西不能被调用者使用,从而实现访问控制,保护类里面一些重要的部分
  • private 默认修饰符 protected public 四种访问修饰符按照从左网易权限依次增大
访问位置 private 默认修饰符 protected public
定义的类中
同一个包中 ×
子类中 × ×
其它包中 × × ×

非访问修饰符

static

  • static:静态
    • 可以修饰变量、函数
    • 类在加载到内存的时候最先加载进来的部分是静态的成员
    • 静态成员的访问不需要依赖对象,可直接通过类名访问: 类名.static属性; 类名.static方法();
    • 静态成员在内存中只保存一份,生命周期跟类保持一致,所以静态成员是共享的
    • 一般不常改动的数据工具类适合声明为静态的
  • 访问
    • 不用实例化对象即可调用
    • static 方法只能访问 static 的属性和方法
    • 非 static 的属性和方法使用实例化对象进行访问

final

  • final:最终的
    • 被 final 修饰的变量它的值不能再做修改
    • 被 final 修饰的函数,不能被重写
    • 被 final 修饰的类,不能被继承
  • final声明一个常量,标识符全部使用大写
  • 全局常量: public static final LP_LOGIN_BIN=”xxxxx”;

abstract

  • abstract:抽象的

    1
    2
    3
    4
    5
    public abstract class ExecelData {
    //抽象方法没有方法体
    public abstract void func();

    }
  • 抽象类

    • 使用 abstract 关键字进行声明
    • 不能直接实例化进行操作(不能 new 对象),通过之类继承完成
    • 子类需要实现抽象类中全部抽象方法
  • 抽象方法

    • 只声明而未实现的方法(没有方法体)
    • 使用 abstract 进行声明
  • 抽象类是一种模板设计的模式

  • 在抽象类中,既可以有具体实现的方法,又有没有具体实现的抽象方法

  • 象类之所以被称为抽象类,就是因为它包含有抽象方法。含有抽象方法的类叫做抽象类

interface

  • interface:接口

    1
    2
    3
    public interface Action {
    public Event execute(RequestContext context) throws Exception;
    }
  • 接口

    • 使用 interface 关键字进行声明,类名前没有 class
    • 接口是一种比抽象类还抽象的一种类
    • 接口中只能定义方法不能有实现了的方法
    • 在这个接口中,定义了一个没有具体实现的方法,方法名叫做execute(),返回类型是Event。如前面所述,接口中的方法都是没有实现的。这些方法的具体实现是在实现(implements)这个接口的类中给出的
    • 实现接口通过 implements 关键字声明

抽象类和接口的比较

概述
  • 一个软件设计的好坏,我想很大程度上取决于它的整体架构,而这个整体架构其实就是你对整个宏观商业业务的抽象框架,当代表业务逻辑的高层抽象层结构 合理时,你底层的具体实现需要考虑的就仅仅是一些算法和一些具体的业务实现了。当你需要再开发另一个相近的项目时,你以前的抽象层说不定还可以再次利用
  • 面对对象的设计,复用的重点其实应该是抽象层的复用,而不是具体某一个代码块的复用
  • 说到了抽象,我就不能不提到曾让我头痛的Java接口和Java抽象类了
  • 既然面向对象设计的重点在于抽象,那Java接口和Java抽象类就有它存在的必然性了。
  • Java接口(interface)和Java抽象类(abstract class)代表的就是抽象类型,就是我们需要提出的抽象层的具体表现。OOP面向对象的编程,如果要提高程序的复用率,增加程序 的可维护性,可扩展性,就必须是面向接口的编程,面向抽象的编程,正确地使用接口、抽象类这些有用的抽象类型作为你结构层次上的顶层。
  • Java接口和Java抽象类有太多相似的地方,又有太多特别的地方,究竟在什么地方,才是它们的最佳位置呢?把它们比较一下,你就可以发现了
区别
  • Java接口和Java抽象类最大的一个区别,就在于Java抽象类可以提供某些方法的部分实现,而Java接口不可以(就是interface中只能定义方法,而不能有方法的实现,而在abstract class中则可以既有方法的具体实现,又有没有具体实现的抽象方法),这大概就是Java抽象类唯一的优点吧,但这个优点非常有用。如果向一个抽象类里加入一个新的具体方法时,那么它所有的子类都一下子都得到了这个新方法,而Java接口做不到这一点,如果向一个Java接口里加入一个 新方法,所有实现这个接口的类就无法成功通过编译了,因为你必须让每一个类都再实现这个方法才行,这显然是Java接口的缺点。倾向于使用抽象类,而不是接口,因为这更容易扩展。
  • 一个抽象类的实现只能由这个抽象类的子类给出,也就是说,这个实现处在抽象类所定义出的继承的等级结构中,而由于Java语言的单继承性,所以抽象类作为类型定义工具的效能大打折扣。在这一点上,Java接口的优势就出来了,任何一个实现了一个Java接口所规定的方法的类都可以具有这个接口的类型,而一个类可以实现任意多个Java接口,从而这个类就有了多种类型。(使用抽象类,那么继承这个抽象类的子类类型就比较单一,因为子类只能单继承抽象类;而子类能够同时实现多个接口,因为类型就比较多。接口和抽象类都可以定义对象,但是只能用他们的具体实现类来进行实例化。)
  • 从第2点不难看出,Java接口是定义混合类型的理想工具,混合类表明一个类不仅仅具有某个主类型的行为,而且具有其他的次要行为。
  • 结合1、2点中抽象类和Java接口的各自优势,具精典的设计模式就出来了:声明类型的工作仍然由Java接口承担,但是同时给出一个Java 抽象类,且实现了这个接口,而其他同属于这个抽象类型的具体类可以选择实现这个Java接口,也可以选择继承这个抽象类,也就是说在层次结构中,Java 接口在最上面,然后紧跟着抽象类,这下两个的最大优点都能发挥到极至了。这个模式就是“缺省适配模式”。在Java语言API中用了这种模式,而且全都遵循一定的命名规范:Abstract +接口名。(A extends AbstractB implements interfaceC,那么A即可以选择实现(@Override)接口interfaceC中的方法,也可以选择不实现;A即可以选择实现(@Override)抽象类AbstractB中的方法,也可以选择不实现)
目的
  • Java接口和Java抽象类的存在就是为了用于具体类的实现和继承的,如果你准备写一个具体类去继承另一个具体类的话,那你的设计就有很大问题了。Java抽象类就是为了继承而存在的,它的抽象方法就是为了强制子类必须去实现的。
  • 使用Java接口和抽象Java类进行变量的类型声明、参数是类型声明、方法的返还类型说明,以及数据类型的转换等。而不要用具体Java类进行变量的类型声明、参数是类型声明、方法的返还类型说明,以及数据类型的转换等。