API
概述
- 全称叫Application Programming Interface, 应用程序编程接口, 其实就是JDK提供的具有各种功能的类和接口.
名词解释:
- API的本意指的是: JDK提供的类和接口
- 我们常说的"打开API"其实指的是"打开API的帮助文档"
- 关于API的学习, 前期你不需要关心这些类和接口的底层是怎么写的, 只要会用就行, 用的多了, 我们才会逐渐去看源码.
API查找步骤:
-
找到你要查找的类
-
看下类所在的包
java.lang包下的类可以直接使用, 无需导包
其它包下的类用之前必须先导包
-
大概的看下类的结构, 知道它有哪些父类, 父接口, 子类等
-
大概的看下类的说明, 知道这个类是干嘛的即可
-
看下该类有无构造方法
有: 说明该类的方法大多数都是非静态的, 需要通过 对象名. 的方式调用.
例如: Object, String 无: 说明该类的成员大多数都是静态的, 需要通过 类名. 的方式调用.
例如: Math, Arrays -
调用指定的方法即可
步骤: 写 方法名(); 传参, 接收返回值
通过查看 API帮助文档 我们发现, Scanner中的如下两个方法是和接收 用户录入的字符串相关的, 于是我们拷贝源码如下:
public String next(); 接受用户录入的字符串, 结束标记是: \r\n, 会获取: 空格以前的内容.
public String nextLine(); 接受用户录入的字符串, 结束标记是: \r\n, 会获取: 除了换行以外所有的内容.
补充关于Scanner的小细节问题
- 问题描述:
- 先用Scanner类中的nextInt()方法接收整数, 再用nextLine()接收字符串, 会导致字符串无法录入的情况.
- 产生原因
-
- nextInt() 和 nextLine() 方法的结束标记都是: \r\n
- nextInt()方法只接收用户录入的整数, 不接收最后的: \r\n
- 遗留下来的\r\n被nextLine()方法识别了, 它直接结束
-
- 解决方案
- 先 nextLine() 接收字符串, 然后 nexLine() 接收整数
- 重新调用一次 Scanner#nextLine()
- 重新new一个Scanner对象
- 通过next()方法接收字符串.
- 实际开发做法: 都用字符串接收, 然后把字符串形式的整数转成int类型即可
int a = Integer.parseInt("123"); //相当于: int a = 123;
Object类
概述
- 它是所有类的父类, 所有的类都直接或者间接继承自Object类.
构造方法
-
public Object(); Object类中只有一个空参构造.
成员方法
toString()、equals()
- public String toString();
- 返回该对象的地址值, 无意义, 建议子类都重写该方法, 用来打印 对象的各个属性值
快捷键生成
- 返回该对象的地址值, 无意义, 建议子类都重写该方法, 用来打印 对象的各个属性值
- public boolean equals(Object obj);
- 比较两个对象是否相同, 默认比较地址值, 无意义, 建议子类都重写该方法, 改为比较: 对象的各个属性值
快捷键生成
- 比较两个对象是否相同, 默认比较地址值, 无意义, 建议子类都重写该方法, 改为比较: 对象的各个属性值
结论:
- 实际开发中, 我们认为, 如果同一个类的两个对象 各个属性值都相同, 那么它们就是同一个对象.
Student s1 = new Student("刘亦菲", 33);
Student s2 = new Student("刘亦菲", 33);
虽然它们的地址值不同, 但是它们的属性值相同, 且是同一个类的对象, 实际开发中, 我们就认为它们就是同一个对象.
- Object#equals() 方法默认比较地址值, 无意义, 建议子类都重写该方法, 改为比较: 对象的各个属性值.
案例:测试 toString()、equals() 方法
- JavaBean类
package com.itheima.demo02_object;
//JavaBean类, 表示学生.
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
//重写Object类的equals()方法, 比较对象的属性值是否相同。
@Override
public boolean equals(Object obj) { //s1.equals(s2)
/*
s1: this
s2: obj student
*/
//1. 提高效率, 有可能要比较的两个对象是同一个类型的对象.
if (this == obj) //比较:地址值
return true;
//2. 提高健壮性, 有可能要比较 的两个对象不是同一个类型的对象.
if (obj == null || this.getClass() != obj.getClass()) return false;
//3. 向下转型
Student student = (Student) obj;
//4. 比较两个对象的年龄是否相同.
if (this.age != student.age) return false;
//5. 比较两个对象的姓名是否相同.
//这里的equals()指的是: String类中的equals()方法
return this.name != null ? this.name.equals(student.name) : student.name == null;
}
//重写Object#toString()方法
//快捷键生成
@Override
public String toString() {
/*return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';*/
//自定义toString()方法的内容
return name + "..." + age;
}
}
- 测试类
package com.ithiema.api.demo;
import com.ithiema.api.pojo.Student;
public class Demo02 {
public static void main(String[] args) {
Student s = new Student("刘亦菲", 33);
System.out.println(s.toString());
System.out.println(s);
Student s1 = new Student("刘亦菲", 33);
Student s2 = new Student("刘亦菲", 33);
//比较: 引用类型.
System.out.println(s1 == s2); //false, 比较地址值.
System.out.println(s1.equals(s2)); //true, 重写后, 比较的是: 对象的属性值.
System.out.println("-----------------");
//比较: 基本类型
System.out.println(10 == 20); //比较的是: 数值
//System.out.println(10.equals(10)); //这样写会报错.
}
}
补充案例: == 和 equals()的区别是什么?
-
作用范围不同
==: 既可以用于比较基本类型, 也可以用来比较引用类型
equals(): 只能用于比较引用类型
-
作用不同
==: 比较基本类型比较的是 数值, 比较引用类型比较的是 地址值
equals(): Object#equals()默认比较地址值, 无意义, 建议子类都重写它
-
本质不同
==: 是运算符
equals(): 是方法
String类
概述
- 它表示字符串, 所有的字符串实例都是它的对象, 且字符串一旦初始化 其值就不能发生改变.
- 它的本质(底层)就是一个 字符数组, 字符串每个元素(字符)也是有编号的, 编号从 0 开始.
特点
- 字符串值是一个常量, 如果是免new创建则在常量池, 如果是new创建则在 堆区.
- 字符串值是一个常量, 其值一旦初始化就不能改变.
- 字符串中每一个字符都是有索引的, 且索引是从 0 开始数的.
构造方法
public String();
public String(String s);
public String(char[] chs);
public String(char[] chs,int start,int len); start:表示起始索引,len:表示个数
public String(byte[] bys);
public String(byte[] bys,int start,int len); start:表示起始索引,len:表示个数
实际开发中, 我们最常用的创建字符串的格式如下:
String str = “abc”; //语法糖.
public class StringDemo01 {
public static void main(String[] args) {
//1. 演示 public String(); 通过空参构造, 创建字符串对象.
String s1 = new String();
System.out.println("s1: " + s1); //输出的不是地址值, 说明String重写了Object#toString().
System.out.println("-------------------");
//2. 演示 public String(String s); 通过带参构造, 创建字符串对象.
String s2 = new String("abc");
System.out.println("s2: " + s2);
System.out.println("-------------------");
//3. 演示 public String(char[] chs); 把接收到的字符数组, 转成其对应的字符串形式.
char[] chs = {'h', 'e', '黑','马','程','序','员', 'l', 'l', 'o'};
String s3 = new String(chs);
System.out.println("s3: " + s3);
System.out.println("-------------------");
//4. 演示public String(char[] chs, int index, int count); 把接收到的字符数组的一部分, 转成其对应的字符串形式.
String s4 = new String(chs, 2, 5);
System.out.println("s4: " + s4);
System.out.println("-------------------");
//5. 演示public String(byte[] bys); 把接收到的字节数组, 转成其对应的字符串形式.
byte[] bys = {97, 98, 99, 65, 66};
String s5 = new String(bys);
System.out.println("s5: " + s5); //abcAB
System.out.println("-------------------");
//6. 演示public String(byte[] bys, int index, int count); 把接收到的字节数组的一部分, 转成其对应的字符串形式.
String s6 = new String(bys, 1, 2);
System.out.println("s6: " + s6);
System.out.println("-------------------");
//7. 实际开发写法
String s7 = "abc"; //语法糖.
System.out.println("s7: " + s7);
}
}
成员方法
equals();
equalsIgnoreCase();
length();
charAt();
toString();
toCharArray();
Java中的常量优化机制
-
针对于byte类型:
- 如果是变量相加:会提升类型,然后再运算
- 类型提升顺序:byte, short, char -> int -> long -> float -> double
- 如果是常量相加:会直接运算,然后看结果在不在左边的数据范围内,在不报错,不在就报错。
- 如果是变量相加:会提升类型,然后再运算
-
针对于String类型:
- 如果是变量拼接:会直接拼接, 不会在(堆区)开辟新空间
- 如果是常量拼接:会在堆区开辟新空间
public class StringDemo04 {
public static void main(String[] args) {
byte b1 = 3;
byte b2 = 4;
byte b3 = 3 + 4;
//byte b4 = b1 + b2; //这行代码会报错, 因为提升数据类型了.
System.out.println("-------------------------------");
String s1 = "abc";
String s2 = "ab";
String s3 = "c";
//System.out.println(s1 == (new StringBuilder()).append(s2).append(s3).toString());
System.out.println(s1 == s2 + s3); //false
//System.out.println(s1 == (new StringBuilder()).append(s2).append("c").toString());
System.out.println(s1 == s2 + "c"); //false
//System.out.println(s1 == "abc")
System.out.println(s1 == "ab" + "c"); //true
}
}
equals()、equalsIgnoreCase()
equals(Object obj): 比较两个字符串是否相等, 比较的是内容, 区分大小写
equalsIgnoreCase(String s): 比较两个字符串是否相等, 比较的是内容, 不区分大小写
package com.itheima.demo03_string;
//案例: 演示字符串的比较
public class StringDemo03 {
public static void main(String[] args) {
//1.定义字符数组chs, 初始化值为: 'a, 'b', 'c', 这三个字符 .
char[] chs = {'a', 'b', 'c'};
//2.将其分别封装成s1, s2这两个字符串对象.
String s1 = new String(chs);
String s2 = new String(chs);
//3.直接通过""的方式创建两个字符串对象s3和s4.
String s3 = "abc";
String s4 = "aBc";
//4.通过==分别判断s1和s2, s1和s3, s3和s4是否相同.
System.out.println(s1 == s2); //false
System.out.println(s2 == s3); //false
System.out.println(s3 == s4); //false
System.out.println("-------------------");
//5.通过equals()分别判断s1和s2, s1和s3, s3和s4是否相同.
System.out.println(s1.equals(s2)); //true
System.out.println(s1.equals(s3)); //true
System.out.println(s3.equals(s4)); //false
System.out.println("-------------------");
//6.通过equalsIgnoreCase()判断字符串abc和ABC是否相同.
System.out.println(s3.equalsIgnoreCase("ABC")); //true
}
}
案例:模拟用户登录, Scanner, String, if.else <=> 三元, for循环
package com.itheima.demo04_exercise;
//但凡是写到这个包下的类, 都是你今天晚上要敲的代码, 每个至少3遍.
import java.util.Scanner;
//案例: 模拟用户登录, Scanner, String, if.else <=> 三元, for循环
public class Demo01 {
public static void main(String[] args) {
/*
需求:
1.模拟用户登录, 只给3次机会, 登录成功则提示"欢迎您, ***".
2.登录失败则判断是否还有登录机会, 有则提示剩余登录次数, 没有则提示"您的账号已被锁定".
3.假设初始化账号和密码分别为: "传智播客", "黑马程序员".
*/
//1. 创建键盘录入对象.
Scanner sc = new Scanner(System.in);
//2. 设定初始账号和密码.
String username = "传智播客";
String password = "黑马程序员";
//3. 因为只给3次机会, 所以用for循环.
for (int i = 0; i < 3; i++) {
//4. 提示用户录入账号和密码, 并接收.
System.out.println("请录入您的账号: ");
String uname = sc.nextLine();
System.out.println("请录入您的密码: ");
String pw = sc.nextLine();
//5. 判断用户录入的账号和密码是否正确.
//5.1 如果正确, 提示登录成功, 然后循环结束.
if (username.equals(uname) && password.equals(pw)) {
//System.out.println("登陆成功!");
System.out.println("欢迎您, " + uname);
break; //细节.
} else {
//5.2 如果错误, 判断是否还有登陆机会.
//5.2.1 如果有, 则提示: 登陆失败, 你还有*次机会.
if (i != 2) {
System.out.println("登陆失败, 你还有" + (2 - i) + "次机会.");
} else {
//5.2.2 如果没有, 提示: 账号锁定.
System.out.println("账号被锁定, 请于管理员联系 110");
}
}
}
}
}
length(),charAt()
- public int length(); 获取字符串的长度
- public char charAt(int index) 根据索引, 获取其对应的字符.
- 小细节:
字符串的底层其实就是一个字符数组, 所以字符串中每个元素都是由编号的, 编号是从0开始的.
public class Demo02 {
public static void main(String[] args) {
String str = "abc";
//1. 演示length方法
System.out.println("length方法: " + str.length()); //3
//2. 演示charAt()方法.
System.out.println("charAt方法: " + str.charAt(2)); //c
//StringIndexOutOfBoundsException: 字符串索引越界异常.
//System.out.println("charAt方法: " + str.charAt(20)); //报错
//需求: 键盘录入一个字符串, 使用程序实现在控制台遍历打印该字符串.
//1. 创建键盘录入对象.
Scanner sc = new Scanner(System.in);
//2. 提示用户录入并接收字符串.
System.out.println("请录入一个字符串: ");
String s = sc.nextLine();
//3. 通过for循环, 遍历字符串, 获取字符串中的每一个索引值.
for (int i = 0; i < s.length(); i++) {
//i就是字符串中, 每个字符的索引
//4. 根据索引, 获取到字符串中的每一个字符.
char ch = s.charAt(i);
//5. 打印结果.
System.out.println(ch);
}
}
}
案例: 统计各类型字符的次数
package com.itheima.demo04_exercise;
import java.util.Scanner;
//案例: 统计各类型字符的次数
public class Demo03 {
public static void main(String[] args) {
/*
需求:
键盘录入一个字符串, 统计该字符串中大写字母字符, 小写字母字符, 数字字符出现的次数.
注意: 不考虑其他字符, 例如@, !, \, /等
*/
//1. 提示用户录入并接收.
Scanner sc = new Scanner(System.in);
System.out.println("请录入一个字符串: ");
String str = sc.nextLine();
//2. 定义三个int类型的变量, 分别表示: 大写字母字符, 小写字母字符, 以及数字字符的次数.
int bigCount = 0, smallCount = 0, numberCount = 0;
//3. 通过for循环, 遍历字符串, 获取到每一个字符.
for (int i = 0; i < str.length(); i++) {
//获取到每一个字符
char ch = str.charAt(i);
//4. 判断当前遍历到的字符属于哪种字符, 是哪种, 对应的计数器就++
if (ch >= 'A' && ch <= 'Z') {
//大写字母字符
bigCount++;
} else if(ch >= 'a' && ch <= 'z') {
//小写字母字符
smallCount++;
} else if(ch >= '0' && ch <= '9') {
//数字字符
numberCount++;
}
}
//5. 循环结束后, 打印各个计数器的值即可.
System.out.println("大写字母字符的个数: " + bigCount);
System.out.println("小写字母字符的个数: " + smallCount);
System.out.println("数字字符的个数: " + numberCount);
}
}
案例: 演示字符串拼接
package com.itheima.demo04_exercise;
//案例: 演示字符串拼接.
/*
涉及到的字符串中的方法:
public String concat(String str); 拼接字符串, 返回新串.
*/
public class Demo04 {
public static void main(String[] args) {
//演示concat()方法, 了解即可, 实际开发写的比较少.
String s1 = "ab";
String s2 = "c";
String s3 = s1 + s2; //s3 = "abc", 会开辟空间(堆)
String s4 = s1.concat(s2); //s4 = "abc", 不会开辟堆空间.
System.out.println("s3: " + s3);
System.out.println("s4: " + s4);
System.out.println("--------------------");
/*
需求:
1.定义方法arrayToString(), 把int数组的元素按照指定的格式拼接成一个字符串, 并返回.
2.在main方法中, 调用上述的方法.
3.例如: 数组为int[] arr = {1, 2, 3}, 则拼接后, 结果为: [1, 2, 3]
*/
//2. 调用方法
//int[] arr = {1, 2, 3};
int[] arr = null;
System.out.println(array2String(arr));
}
//1. 定义方法arrayToString(), 把int数组的元素按照指定的格式拼接成一个字符串, 并返回.
//定义为static是因为尚明main方法调用时,静态只能访问静态。
public static String array2String(int[] arr) {
//先做越界处理.
if (arr == null || arr.length == 0)
return "[]";
//正常的拼接逻辑.
String s = "[";
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1)
s += (arr[i] + "]");
else
s += (arr[i] + ", ");
//通过三元优化,自己写.
}
return s;
}
}
案例: 演示字符串反转
package com.itheima.demo04_exercise;
import java.util.Scanner;
//案例: 演示字符串反转.
public class Demo05 {
public static void main(String[] args) {
/*
需求:
1.定义方法reverse(), 实现字符串的反转.
2.在main方法中键盘录入一个字符串, 调用上述的方法后, 在控制台输出结果.
3.例如: 键盘录入abc, 输出结果cba.
*/
//2. 提示用户录入字符串, 并接收.
Scanner sc = new Scanner(System.in);
System.out.println("请录入一个字符串: ");
String str = sc.nextLine();
//3. 调用方法.
System.out.println(reverse(str));
}
//1. 定义方法reverse(), 实现字符串的反转. 思路: 就是倒序输出字符串, 然后拼接即可.
public static String reverse(String s) {
//1.1 定义字符串, 记录反转后的结果.
String newStr = "";
//1.2 遍历原始字符串, 然后倒序输出.
for (int i = s.length() - 1; i >= 0; i--) {
//1.3 拼接结果.
newStr += s.charAt(i);
}
//1.4 返回具体的结果.
return newStr;
}
}
String类中的常用方法演示:
- 判断功能: (返回值:Boolean)//首尾中空加判断
startsWith();
endsWIth();
isEmpty();
equals();
equalsIgnoreCase();
- 获取功能: //截长取位取元素
subString(); //2个重载
length();
indexOf(); //2个重载
lastIndexOf(); //2个重载
charAt();
- 转换功能 //大小拼串转数组
toUpperCase();
toLowerCase();
concat();
toCharArray();
getBytes(); //2个重载
- 其他功能 //除空切换字典排
trim();
split();
replace();
replaceAll();
compareTo();
startWith(),contains()
需求:已知有1, 2, 3, 4 这四个数字, 问它们能组合成的四位数字形式有哪些, 并将结果打印到控制台上.
要求:该四位数字必须包含1, 2, 3, 4 这四个数字.
需求:数字4不能开头,数字1和3不能挨着,按照5个一行顺序打印
package com.ithiema.api.demo;
import java.util.Scanner;
public class Demo09 {
public static void main(String[] args) {
for (int i = 1234, count = 0; i <= 4321; i++) {
//核心思路:把i(int) -> 字符串,然后通过String类中的方法做校验
String s = "" + i;
if (s.contains("1") && s.contains("2") && s.contains("3")
&& s.contains("4") && !s.startsWith("4")
&& !s.contains("13") && !s.contains("31")) {
System.out.print(++count % 5 == 0 ? s + "\r\n" : s + "\t");
}
}
}
}
StringBuilder类
概述:
- 它是java.lang包下的类,可以直接使用,无需导包
- 它表示可变的字符串序列,即:它的内容是可变的,所以该类也叫:字符串缓冲序列
作用:
- 一般应用于大量的字符串的拼接操作,因为不会频繁的开辟空间,而是在对象内部直接做拼接,所以效率相对较高
构造方法
public StringBulider(); 创建字符串缓冲区类对象,封装:空参
public StringBulider(String s); 创建字符串缓冲区,封装:指定的字符串内容。
成员方法
public StringBuilder append(Object obj); 添加元素到StringBuilder中, 返回该对象本身.
public StringBuilder reverse(); 反转内容, 返回该对象本身.
演示StringBuilder中的方法
package com.itheima.demo05_stringbuilder;
public class Demo02 {
public static void main(String[] args) {
//1.通过空参构造创建StringBuilder类的对象sb.
StringBuilder sb = new StringBuilder();
//2.通过append()方法, 往sb对象中添加"hello",然后用sb2对象接收.
StringBuilder sb2 = sb.append("hello");
//3.打印对象sb和sb2的结果, 并观察.
System.out.println("sb: " + sb); //sb: hello
System.out.println("sb2: " + sb2); //sb2: hello
System.out.println(sb == sb2); //比较的是地址值, true
//实际开发中, append()方法的调用写法.
//如果是单个添加
sb.append("world");
//如果是添加多个, 用链式思想实现.
//复杂写法
/* sb.append("传智播客");
sb.append("黑马程序员");
sb.append("夯哥");*/
//链式编程解释: 如果一个方法的返回值还是对象, 我们可以在后边接着 .方法(), 这种写法就叫链式编程.
sb.append("传智播客").append("黑马程序员").append("夯哥");
System.out.println("sb: " + sb); //sb: helloworld
System.out.println("---------------------------");
//4.通过reverse()方法, 来反转上述的内容.
StringBuilder sb3 = sb2.reverse();
System.out.println("sb: " + sb);
System.out.println("sb2: " + sb2);
System.out.println("sb3: " + sb3);
System.out.println(sb2 == sb3);
}
}
链式编程解释:如果一个方法的返回值还是对象, 我们可以在后边接着 .方法(), 这种写法就叫链式编程.
sb.append(“传智播客”).append(“黑马程序员”).append(“夯哥”);
演示StringBuilder和String之间的相互转换
String 对象 -> StringBuilder 对象
public StringBuilder(String str); 带参构造, 创建 StringBuilder 对象.
StringBuilder 对象 -> String 对象
StringBuilder 类中的 toString()方法
public String toString(); 返回该对象的字符串形式.
package com.itheima.demo05_stringbuilder;
public class Demo03 {
public static void main(String[] args) {
//1.定义空参不可变StringBuilder对象, 往里边添加完"hello"字符串后, 再将其转成String类型的对象.
StringBuilder sb = new StringBuilder();
sb.append("hello");
String s1 = sb.toString(); // StringBuilder对象 -> String对象
System.out.println("s1: " + s1);
System.out.println("--------------------");
//2.将String字符串转成StringBuilder对象, 然后打印.
String s2 = "传智播客";
StringBuilder sb2 = new StringBuilder(s2); //String对象 -> StringBuilder对象
System.out.println("sb2: " + sb2);
}
}
案例: 拼接字符串,StringBuilder(), append(), toString()
package com.itheima.demo04_exercise;
//案例: 拼接字符串.
public class Demo06 {
public static void main(String[] args) {
//1.定义方法arrayToString(), 把int数组的元素按照指定的格式拼接成一个字符串, 并返回.
//2.在main方法中, 调用上述的方法.
//3.例如: 数组为int[] arr = {1, 2, 3}, 则拼接后, 结果为: [1, 2, 3]
//int[] arr = null;
int[] arr = {1, 2, 3};
System.out.println(array2String(arr));
}
//1. 定义方法arrayToString(), 把int数组的元素按照指定的格式拼接成一个字符串, 并返回.
public static String array2String(int[] arr) {
//1. 非法值校验.
if (arr == null || arr.length == 0)
return "[]";
//2. 创建StringBuilder对象.
StringBuilder sb = new StringBuilder("[");
//3. 正常的拼接, 用if.else实现.
/* for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) //最后一个元素
sb.append(arr[i]).append("]");
else
sb.append(arr[i]).append(", ");
}*/
//3. 正常的拼接, 用三元实现
for (int i = 0; i < arr.length; i++)
sb.append(arr[i]).append(i == arr.length - 1 ? "]" : ", ");
return sb.toString();
}
}
案例: StringBuilder案例, 反转字符串
思路: String对象 -> StringBuilder对象 -> 调用StringBuilder对象的reverse()方法 -> 重新换成String对象.
package com.itheima.demo04_exercise;
import java.util.Scanner;
public class Demo07 {
public static void main(String[] args) {
//2.在main方法中键盘录入一个字符串, 调用上述的方法后, 在控制台输出结果.
//3.例如: 键盘录入abc, 输出结果cba.
Scanner sc = new Scanner(System.in);
System.out.println("请录入一个字符串: ");
String str = sc.nextLine();
//方式一: 调用自定义方法
System.out.println(reverse(str));
System.out.println("------------------------");
//方式二: 链式编程.
//思路: String对象 -> StringBuilder对象 -> 调用StringBuilder对象的reverse()方法 -> 重新换成String对象.
String reverseStr = new StringBuilder(str).reverse().toString();
System.out.println(reverseStr);
}
//1.定义方法reverse(), 实现字符串的反转.
public static String reverse(String s1) {
//1. 把String -> StringBuilder对象.
StringBuilder sb = new StringBuilder(s1);
//2. 调用StringBuilder#reverse(), 反转内容.
sb.reverse();
//3. 把StringBuilder -> String, 然后返回.
return sb.toString();
}
}
StringBuilder 和 StringBuffer之间的区别:
1. String和其他两个类型的区别:
String: 长度固定.
其他两个类型: 长度可变.
2. StringBuilder和 StringBuffer之间的区别:
StringBuilder: JDK1.5出来的, 它里边的方法都是线程不安全(线程不同步), 效率稍高.
StringBuffer: JDK1.0出来的, 它里边的方法都是线程安全(线程同步), 效率稍低.
冒泡排序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DiRiUZpP-1669232825706)(F:\BigData\java\图片\day09图片\01.冒泡排序原理图.png)]
原理:
相邻元素两两比较, 大的往后走, 这样的话, 第一轮比较完毕后, 最大值就在最大索引处.
package com.itheima.demo01_arrays;
//案例: 演示冒泡排序.
/*
原理:
相邻元素两两比较, 大的往后走, 这样的话, 第一轮比较完毕后, 最大值就在最大索引处.
*/
public class Demo01 {
public static void main(String[] args) {
/*
需求:
1.已知数组int[] arr = {25, 69, 80, 57, 13}, 请编写代码对齐进行升序排序.
2.即: 排序后结果为: arr = {13, 25, 57, 69, 80};
*/
//1. 定义数组, 记录要排序的元素.
int[] arr = {25, 69, 80, 57, 13};
//2. 通过外循环, 控制比较的轮数.
//这里的-1是为了啥? 为了提高效率.
for (int i = 0; i < arr.length - 1; i++) {//0, 1, 2, 3
//3. 通过内循环, 控制每轮比较的次数.
/*
这里的-1是为了啥? 为了防止出现索引越界异常.
这里的-i是为了啥? 为了提高效率.
*/
for (int j = 0; j < arr.length - 1 - i; j++) { //4, 3, 2, 1
//4. 如果前一个元素比后一个元素大, 就交换它们的位置.
//即: arr[j] 和 arr[j + 1] 比较
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
//5. for循环执行结束后, 已经排好序了, 我们直接打印数组即可.
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
Arrays工具类
概述:
- 它是针对于数组的工具类。里面提供了大量针对于数组的操作,例如:对数组元素排序,把数组元素拼接成字符串等。
工具类介绍:
- 成员都是静态的, 可以通过 类名. 的形式直接调用
- 构造方法私有化
成员方法
- public static String toString(int[] arr) 把数组转成其对应的字符串形式, 例如: [1, 3, 5, 6]
- public static void sort(int[] arr) 对数组元素进行升序排序.
package com.itheima.demo01_arrays;
import java.util.Arrays;
//案例: 演示Arrays工具类的使用.
public class Demo02 {
public static void main(String[] args) {
//1.已知数组int[] arr = {25, 69, 80, 57, 13}.
int[] arr = {25, 69, 80, 57, 13};
//补充: 打印排序前的结果 排序前: [25, 69, 80, 57, 13]
System.out.println("排序前: " + Arrays.toString(arr));
//2.通过Arrays#sort()方法, 对其升序排列.
Arrays.sort(arr);
//3.打印排序后的结果. 排序后: [13, 25, 57, 69, 80]
System.out.println("排序后: " + Arrays.toString(arr));
}
}
- 一个小问题:
- 通过翻看API帮助文档,我们发现Arrays工具类并没有提供构造方法,这是为什么?
- 如果我们不写构造方法,系统会默认给一个 公共的无参构造,那为什么找不到?
- 答案:
- 因为Arrays类中提供了一个私有的无参构造方法,所以系统就不再提供构造方法了,又因为是私有成员所以API不显示。
包装类
-
概述:
- 所谓的的包装类指的就是基本类型对应的引用类型,之所以有包装类,目的就是为了把基本类型封装成对象,方便我们管理。
-
对应的关系:
-
基本类型 对应的引用类型(包装类) byte Byte short Short char Character int Integer long Long float Float double Double boolean Boolean
-
-
包装类的主要作用:
- 主要用于 该类型对应的基本类型 和 String类型的数据之间 相互转换。
-
例如:
-
Interger 主要用于把 字符串形式的数字,转换成int类型
- int num = Integer.parseInt(“123”);
-
Double 主要用于把 字符串形式的小数,转换成double类型
- double d = Double.parseDouble(“12.3”);
-
Boolean 主要用于把 字符串形式的布尔值,转换成boolean类型
- boolean flag = Boolean.parse.Boolean(“false”);
-
Integer类
-
概述
- 它是基本类型int对应的 引用类型(即:包装类),主要提供了针对 int 和 String 相互转换的一些方法
-
构造方法
public Integer(int i); 创建Integer类型的对象,封装:整数
public Integer(String s); 创建Integer类型的对象,封装:字符串形式的整数,如果不是纯数字,会报错
package com.itheima.demo02_integer;
//案例: 演示Integer类的构造方法.
public class Demo01 {
public static void main(String[] args) {
//1.通过上述的两个构造方法, 分别创建Integer类型的对象.
//1.1 演示: public Integer(int value);
Integer i1 = new Integer(10);
//1.2 演示: public Integer(String value);
Integer i2 = new Integer("123");
//Integer i2 = new Integer("123a"); 这样写会报错.
//2.在main方法中, 打印创建好的Integer对象.
System.out.println("i1: " + i1);
System.out.println("i2: " + i2);
System.out.println("----------------------------");
//3. 演示Integer类中的两个常量
System.out.println(Integer.MAX_VALUE); //int类型的最大值
System.out.println(Integer.MIN_VALUE); //int类型的最小值
}
}
演示int和String之间的相互转换
-
int -> String
-
int a = 10; String s = "" + a; //推荐使用
-
-
String -> int
-
String s = "123"; //必须是 纯数字 形式的字符串 int i = Integer.parseInt(s);
-
package com.itheima.demo02_integer;
//案例: 演示int和String之间的相互转换.
public class Demo02 {
public static void main(String[] args) {
//需求1: int -> String
//方式一: 直接在数值后边拼接 "", 推荐使用.
int a = 10;
String s1 = "" + a;
System.out.println("s1: " + s1);
//方式二: String#valueOf()
String s2 = String.valueOf(111);
System.out.println("s2: " + s2);
System.out.println("-----------------------------");
//需求2: String -> int, 必须是纯数字形式的字符串
//方式1: 转换思路 String -> Integer -> int
String s3 = "123";
//String -> Integer
Integer i1 = new Integer(s3);
//Integer -> int
int num1 = i1.intValue();
System.out.println("num1: " + num1);
//方式2: 通过Integer#parseInt();方法实现, 推荐使用.
int num2 = Integer.parseInt(s3);
System.out.println("num2: " + num2);
}
}
案例:字符串切割,然后排序,并拼接,然后打印
提示:
- 通过String类的split(String regex)方法,可以按照指定字符切割字符串
- public String[] split(String regex); 根据给定的字符串,切割字符串,获取字符串数组
- public String subString(int start,int end); 根据索引截取指定范围的内容,包左不包右
package com.ithiema.api.demo;
import java.util.Arrays;
public class Demo14 {
public static void main(String[] args) {
//1.定义String s,记录要操作的字符串
String s = "91 27 45 38 50";
//2.对其按照 空格 进行切割,获取String[]
String[] strArr = s.split(" ");
//3.定义长度与其一模一样的int[] ,来存储转换后的数据。
int[] arr = new int[strArr.length];
//4.遍历字符串数组,获取其中的每一个字符串
for (int i = 0; i < strArr.length; i++) {
//5.将其转成整数后,存储到:数组中
arr[i] = Integer.parseInt(strArr[i]);
}
//6.对数组元素进行排序
Arrays.sort(arr);
//7.将(排序后)的数组元素拼接成指定的字符串
String str = Arrays.toString(arr);
//思路1:截取
String s1 = str.substring(1, str.length() - 1);
System.out.println(s1);
//思路2:替换
String s2 = str.replace("[", "").replace("]", "");
//8.打印输出
System.out.println(s2);
}
}
案例: 演示其他基本类型的数据 和 String之间如何相互转换
-
包装类中都有一个方法, 叫 parseXxx(), 用于把字符串形式的 该类型数据, 转成对应的 基本类型, Character类型除外
-
Integer.parseInt("纯数字类型的字符串值"); 用于把 String -> int Double.parseDouble("纯数字类型的字符串值"); 用于把 String -> double Boolean.parseBoolean("字符串形式的true或者false"); 用于把 String -> boolean
-
因为字符串的本质就是一个字符数组, 所以字符和字符串之间的转换有特殊的方式
-
场景1: 单字符 和 字符串之间相互转换. char -> String String s1 = 'a' + ""; String -> char char ch = "abc".charAt(1); 场景2: 字符数组 -> 字符串之间相互转换. char[] -> String char[] chs = {'a', 'b', 'c'}; String s = new String(chs); String -> char[] String s = "abc"; char[] chs = s.toCharArray();
package com.itheima.demo02_integer;
public class Demo03 {
public static void main(String[] args) {
//1. 演示除Character之外的, 其他包装类的共性方法.
//String -> int
int num = Integer.parseInt("123");
//String -> double
double d = Double.parseDouble("10.3");
//String -> boolean
boolean flag = Boolean.parseBoolean("false");
System.out.println("num: " + num);
System.out.println("d: " + d);
System.out.println("flag: " + flag);
System.out.println("-------------------------------");
//2. 演示 字符 -> 字符串之间相互转换, 略.
//char -> String
String s1 = 'a' + "";
//String -> char
char ch = "abc".charAt(1);
//3. 演示 字符数组 -> 字符串之间相互转换,
//String -> char[]
String str = "黑马程序员";
char[] chs = str.toCharArray();
//System.out.println(chs); //这里不是地址值,而是数组元素. IO流解释.
for (int i = 0; i < chs.length; i++) {
char c = chs[i];
System.out.println(c);
}
// char[] -> String
String str2 = new String(chs);
System.out.println("str2: " + str2);
}
}
JDK1.5的特性 自动拆装箱
- 装箱:指的是把基本类型的数据转成其对应的引用类型
- 拆箱:指的是把引用类型得数据转成其对应的基本类型
package com.ithiema.api.demo;
public class Demo17 {
public static void main(String[] args) {
int a = 10;
Integer i1 = new Integer(a); //装箱
Integer i2 = a; //自动装箱,JDK1.5的特性
int b = i1.intValue();
int c = i1; //自动拆箱,JDK1.5的特性
Integer aa = 3;
aa += 5; //1.自动拆箱 2.做加法运算 3.自动装箱
System.out.println(aa);
}
}
Date类
- 概述:
- Date类表示特定的瞬间,精确到毫秒. 它是java.util包下的类, 用之前需要先导包.
- 1秒 = 1000毫秒
构造方法
- public Date();
- 创建日期类对象,采用:系统默认时间, 单位是毫秒
- public Date(long times);
- 创建日期类对象,采用:指定时间,即:时间种子一样,获取的日期也是一样的,单位是毫秒
细节:
- 你通过Date获取的一个数值,其实就是当前时间 相对于 时间原点的 对应的 毫秒值。
- 标准时间原点:1970年1月1日 00:00:00
- 但是我们用的是北京时间,处于东八区,所以我们计算机用的时间原点是:1970年1月1日 08:00:00
package com.ithiema.api.demo;
import java.util.Date;
public class Demo18 {
public static void main(String[] args) {
//1. 演示 public Date(); 采用当前系统默认时间, 生成Date对象.
Date d1 = new Date();
System.out.println(d1);
//2. 演示 public Date(long time); 采用指定的毫秒值, 生成对应的Date对象.
Date d2 = new Date(1000L); //指定时间 单位毫秒 这里为 1秒
System.out.println(d2);
Date d3 = new Date(0L);
System.out.println(d2);
}
}
成员方法
-
public long getTime(); //获取Date对象对应的 毫秒值.
- 可以计算某段程序的执行时间.
-
public void setTime(long time); //设置当前Date对象的毫秒值为指定的值.
- 我们在日志文件中可以记录一些当前时间的毫秒值, 用的时候把它转成时间对象即可, 方便我们存储和操作.
//案例: 演示Date类的成员方法
package com.itheima.demo04_date;
import java.util.Date;
public class Demo02 {
public static void main(String[] args) {
//1. 采用当前系统默认时间, 创建Date对象.
Date d1 = new Date();
System.out.println(d1); //Mon Jun 01 12:07:33 CST 2020
//2. 获取上述时间对应的毫秒值.
System.out.println(d1.getTime()); //1590984453616
System.out.println("---------------------");
//2. 采用指定的毫秒值, 生成Date对象.
//Date d2 = new Date(1590984453616L);
Date d2 = new Date();
d2.setTime(1590984453616L);
System.out.println(d2);
}
}
扩展:Date在实际开发中的真正应用
- 应用场景:
- 时间对应的毫秒值可以用 日志文件中
- 用来计算某个程序的执行时间
package com.ithiema.api.demo;
import java.util.Date;
public class Demo20 {
public static void main(String[] args) {
Date d1 = new Date();
long start = d1.getTime();
for (int i = 0; i < 10000; i++) {
System.out.println("hello world!" + i);
}
Date d2 = new Date();
long end = d2.getTime();
System.out.println("执行时间为" + (end - start) + "毫秒");
}
}
SimpleDateFormat类
- 概述:
- 它是java.text包下的类,用之前需要导包。
- 它是日期格式化类,主要用来对日期做 格式化 和 解析操作的
- 名词解释:
- 格式化:把Date -> String
- 解析: 把String -> Date,必须是:符合日期格式的字符串。
构造方法
- public SimpleDateFormat(); 采用默认模板.
- public SimpleDateFormat(String pattern); 采用指定模板.
成员方法
-
public final String format(Date date); 日期格式化操作, 即: Date -> String
-
public Date parse(String source); 日期解析操作, 即: String -> Date
package com.ithiema.api.demo;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Demo21 {
public static void main(String[] args) {
Date d = new Date();
System.out.println("格式化前" + d); //Sun Nov 06 16:33:26 CST 2022
SimpleDateFormat sdf = new SimpleDateFormat();
String s = sdf.format(d);
System.out.println("格式化后" + s); //22-11-6 下午4:33
//指定模板
//SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日");
String s2 = sdf2.format(d);
System.out.println(s2);
}
}
DateUtils工具类的定义
package com.ithiema.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtils {
//1.构造方法私有化
private DateUtils() {
}
//2.创建私有的 静态的成员变量,用来表示:日期格式化对象
private static SimpleDateFormat sdf;
//3.定义方法,用来实现格式化操作
/*
* @param d 要被格式化的日期对象
* @param pattern 格式化时采用的模板
* @return 格式化后的字符串对象
* */
public static String date2String(Date d, String pattern){
//1.创建SimpleDateFormat对象
sdf = new SimpleDateFormat(pattern);
//2.格式化操作,并返回结果
//分解版
/*String str = sdf.format(d);
return str;*/
//合并版
return sdf.format(d);
}
//4. 定义方法, 用来实现:日期的解析操作.
/*
* @param strDate 要被解析的字符串形式的日期对象
* @param pattern 解析时采用的模板
* @return解析后的字符串日期对象
*/
public static Date string2Date(String strDate,String pattern) throws ParseException {
sdf = new SimpleDateFormat(pattern);
//分解版
/*Date d = sdf.parse(strDate);
return d;*/
//合并版
return sdf.parse(strDate);
}
}
DateUtils工具类的使用
package com.ithiema.api.demo;
import com.ithiema.utils.DateUtils;
import java.text.ParseException;
import java.util.Date;
public class Demo23 {
public static void main(String[] args) throws ParseException {
Date date = new Date();
//需求1:通过DateUtils工具类实现 格式化操作
//调用工具类方法,格式化
//因为是静态的所以用 类名. 的方式调用该方法
String result = DateUtils.date2String(date, "yyyy-MM-dd HH:mm:ss");
System.out.println(result);
//需求2:通过DateUtils工具类实现 解析操作
String str = "2021年5月12日";
//调用工具类方法,解析
Date date2 = DateUtils.string2Date(str, "yyyy年MM月dd日");
System.out.println(date2);
}
}
Calendar类
- 概述:
- 它是 java.util 包下的类,用之前需要导包。
- 它表示日历类,里面绝大多数的功能都是用来替代 java.util.Date类的
成员常量
public static final int YEAR 年份
public static final int MONTH 月份,0 - 11
public static final int DATE 年中的某一天
public static final int DAY_OF_MONTH 月中的某一天
public static final int DAY_OF_WEEK 星期中的第几天,周日:1,周一:2 ....
public static final int DAY_OF_YEAR 年中的第几天
成员方法
public static Calendar getInstance(); 获取Calendar类的子类对象,即抽象类多态
public int get(int field); 根据给定的日历字段, 获取其对应的值.
public void set(int year, int month, int day) ; 设置时间为指定的(年, 月, 日)
public void add(int field, int count); 设置指定的日历字段, 偏移指定的量.负数往前腿推,正数往后推
入门案例:
package com.ithiema.api.demo;
import java.util.Calendar;
public class Demo24 {
public static void main(String[] args) {
//1.创建Calendar类型的对象,确切的说:它是子类对象
Calendar c = Calendar.getInstance(); //底层其实是:抽象类多态
System.out.println(c);
}
}
演示Calendar中的成员变量和成员方法
案例:Calendar类的功能获取各种日期
package com.ithiema.api.demo;
import java.util.Calendar;
public class Demo25 {
public static void main(String[] args) {
//1.创建Calendar类的对象
Calendar c = Calendar.getInstance();
//2.获取年份,并打印
System.out.println(c.get(Calendar.YEAR));
//3.获取月份,并打印
System.out.println(c.get(Calendar.MONTH + 1));
//4.获取星期中的第几天
System.out.println(c.get(Calendar.DAY_OF_WEEK));
//5.获取月中第几天
System.out.println(c.get(Calendar.DAY_OF_MONTH));
//6.获取年中第几天
System.out.println(c.get(Calendar.DAY_OF_YEAR));
}
}
案例:计算某年的2月有多少天
package com.ithiema.api.demo;
import java.util.Calendar;
import java.util.Scanner;
public class Demo26 {
public static void main(String[] args) {
//1.获取日历;类对象
Calendar c = Calendar.getInstance();
//2.创建键盘录入对象,提示用户录入年份,并接收
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个年份");
int year = sc.nextInt();
//3.设置时间为该年的3月1日
c.set(year, 2, 1); //月份范围:0 ~ 11,2表示3月
//4.把时间往前推1天
c.add(Calendar.DATE, -1);
//5.获取该天是月中第几天,即为:我们要的结果
int day = c.get(Calendar.DATE);
//6.打印结果
System.out.println(year + "年的2月份有" + day + "天");
}
}
内部类
- 概述
- 类里面还有一个类,里面的叫内部类,外面的叫外部类
- 分类
- 成员内部类:写在成员位置的内部类
- 局部内部类:写在局部位置的内部类
- 作用
- 成员内部类:一般应用于底层源代码,主要是用来对外部类的功能做扩展和补充的。(了解)
- 局部内部类:我们用的最多的就是它的一种特殊写法,叫:匿名内部类
package com.ithiema.api.demo;
public class Demo03 {
//成员变量
int a = 10;
//成员内部类
class A {
}
public void show(int b) { //b 和 c都是局部变量
//局部变量
int c = 20;
//局部内部类
class B {
}
}
}
匿名内部类
-
概述
-
指的就是没有名字的 局部内部类。 (局部位置: 方法中, 或者方法的形参列表)
-
格式
new 类名或者接口名() { //重写父类或者父接口中所有的抽象方法 };
-
本质
- 专业版:它是一个 继承了类 或者 实现了接口的 子类的 匿名对象。
- 大白话版: 匿名内部类的本质就是一个:子类对象。
-
应用场景:
-
- 当对 成员方法(也叫:对象方法) 仅调用1次的时候。
-
- 匿名内部类可以作为方法的实参进行传递。(用的最多)
-
-
小技巧:
- 实际开发中,当父类或者父接口中的抽象方法只有1个的时候,我们才会考虑使用匿名内部类。
- 目前刚接触匿名内部类,我们只要抽象方法不超过3个,就可以考虑使用匿名内部类。
匿名内部类用法1_当对成员方法仅调用1次的时候
动物类,父类
package com.itheima.demo07_inner;
//抽象类, 动物类.
public abstract class Animal {
//抽象方法: 表示吃饭.
public abstract void eat();
}
猫类,子类
package com.itheima.demo07_inner;
//表示猫类, 继承Animal
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼!");
a}
}
动物类的测试类
package com.itheima.demo07_inner;
//动物类的测试类, 用来演示: 匿名内部类入门.
public class AnimalTest {
public static void main(String[] args) {
//需求: 调用Animal#eat()方法.
//方式1: 传统做法, 搞一个Animal类的子类, 例如: Cat, 然后通过多态实现.
Animal an = new Cat(); //子类名: Cat, 对象名叫: an
an.eat();
System.out.println("-----------------------");
//方式2: 通过匿名对象实现.
/*
匿名对象解释:
概述:
没有名字的对象, 就叫匿名对象.
特点:
用完以后就会变成垃圾对象, 由GC在不确定的时间回收.
*/
//new Cat(): 就是一个继承了Animal类的子类(Cat)的匿名对象.
new Cat().eat(); //子类名: Cat, 对象名叫: ??
System.out.println("-----------------------");
//方式3: 通过匿名内部类实现.
//匿名内部类的本质: 就是一个继承了Animal类的子类的匿名对象.
new Animal() { //子类名: ??, 对象名叫: ??
//重写类或者接口中所有的抽象方法.
@Override
public void eat() {
System.out.println("我是通过匿名内部类的形式创建的 Animal类的子类对象");
}
}.eat();
//匿名内部类升级版:匿名内部类多态
Animal an2 = new Animal() { //子类名: ??, 对象名叫: ??
//重写类或者接口中所有的抽象方法.
@Override
public void eat() {
System.out.println("我是通过匿名内部类的形式创建的 Animal类的子类对象");
}
};
an2.eat();
an2.eat();
an2.eat();
}
}
匿名内部类用法2_作为方法的实参传递
package com.ithiema.api.demo;
import com.ithiema.api.pojo.Animal;
import com.ithiema.api.pojo.Cat;
public class Demo01 {
public static void main(String[] args) {
//需求:调用Animal#eat()方法
//格式:printAnimal(Animal类型的子类对象);
//方法1:抽象类多态
Animal an = new Cat();
printAnimal(an);
System.out.println("------------------");
//方法2:匿名对象
printAnimal(new Cat());
System.out.println("------------------");
//方法3:匿名内部类
//匿名内部类作为方法的实参传递
printAnimal(new Animal() { //实参
@Override
public void eat() {
System.out.println("匿名内部类,动物会吃");
}
});
}
//定义方法,接收Animal,调用其eat()方法
public static void printAnimal(Animal an) {
an.eat();
}
}
用完以后就会变成垃圾对象, 由GC在不确定的时间回收.
*/
//new Cat(): 就是一个继承了Animal类的子类(Cat)的匿名对象.
new Cat().eat(); //子类名: Cat, 对象名叫: ??
System.out.println("-----------------------");
//方式3: 通过匿名内部类实现.
//匿名内部类的本质: 就是一个继承了Animal类的子类的匿名对象.
new Animal() { //子类名: ??, 对象名叫: ??
//重写类或者接口中所有的抽象方法.
@Override
public void eat() {
System.out.println("我是通过匿名内部类的形式创建的 Animal类的子类对象");
}
}.eat();
//匿名内部类升级版:匿名内部类多态
Animal an2 = new Animal() { //子类名: ??, 对象名叫: ??
//重写类或者接口中所有的抽象方法.
@Override
public void eat() {
System.out.println("我是通过匿名内部类的形式创建的 Animal类的子类对象");
}
};
an2.eat();
an2.eat();
an2.eat();
}
}
##### 匿名内部类用法2_作为方法的实参传递
~~~java
package com.ithiema.api.demo;
import com.ithiema.api.pojo.Animal;
import com.ithiema.api.pojo.Cat;
public class Demo01 {
public static void main(String[] args) {
//需求:调用Animal#eat()方法
//格式:printAnimal(Animal类型的子类对象);
//方法1:抽象类多态
Animal an = new Cat();
printAnimal(an);
System.out.println("------------------");
//方法2:匿名对象
printAnimal(new Cat());
System.out.println("------------------");
//方法3:匿名内部类
//匿名内部类作为方法的实参传递
printAnimal(new Animal() { //实参
@Override
public void eat() {
System.out.println("匿名内部类,动物会吃");
}
});
}
//定义方法,接收Animal,调用其eat()方法
public static void printAnimal(Animal an) {
an.eat();
}
}
~~~