java_API
苟有恒,何必三更眠五更起; 最无益,莫过一日曝十日寒。
API
Java API :指的就是 JDK 中提供的各种功能的 Java类
这些类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,
只需要学习这些类如何使用即可,我们可以通过帮助文档来学习这些API如何使用
String类
创建字符串对象的区别对比
以"" 方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM都只会进阿里一个String对象,并在字符串常量池中维护
字符串常量池
当时用双引号创建字符串对象的时候,系统会检查该字符串师傅在字符串常量池中存在
不存在:创建
存在:不会直接创建而是直接服用
通过new 创建的字符串对象,每一次new都会申请一个内存空间,虽然内容相同,但是地址值不同
char[] chs = {'a', 'b', 'c'};
String s1 = new String(chs);
String s2 = new String(chs);
上面的代码中,JVM会首先创建一个字符数组,然后每一次new的时候都会有一个新的地址
结论:双引号创建的字符串对象,在字符串常量池中存储,通过构造方法创建的字符串对象,在堆内存中存储
String字符串的特点
Java 程序中所有的双引号字符串,都是 String 类的对象
字符串不可变,它们的值在创建后不能被更改
虽然 String 的值是不可变的,但是它们可以被共享
图片上创建两个对象不严谨,如果第一个是bcd跟abc不一样的话就严谨了
只要字符串之间进行拼接,就会生成stringbuilder对象,然后去调用append方法完成拼接
拼接后,再调用toString方法转换成String.
字符串的比较
使用==作比较
基本类型: 比较的是数据值是否相同
引用类型: 比较的是地址值是否相同
字符串是对象,它比较内容是否相同,是通过一个方法来实现的,这个方法叫:equals()
例题(String)
例题1. 模拟登陆
需求:已知用户名和密码,请用程序实现模拟用户登录。
总共给三次机会,登录之后,给出相应的提示
判断是否相等用 username.equals(un)
public static void main(String[] args) {
String username = "admin";
String password = "123";
for (int i = 1; i <=3; i++) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入账号");
String un = sc.nextLine();
System.out.println("请输入密码");
String ps = sc.nextLine();
if(username.equals(un) && password.equals(ps) ){
System.out.println("恭喜!");
break;
}else{
if(i == 3){
System.out.println("您没有机会了"
}else{
System.out.println("你还有"+(3 - i)+"次机会重新输入");
}
}
例题2遍历字符串
需求: 键盘录入一个字符串,使用程序实现在控制台遍历该字符串
方法为 st.charAt(i);
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String st = sc.nextLine();
for(int i=0; i<st.length(); i++) {
st.charAt(i); // 就是指定索引处的字符值
System.out.println(st.charAt(i));
}
}
例题3.案例 :统计字符次数
需求:键盘录入一个字符串,统计该字符串中大写字母字符,小写字母字符,数字字符出现的次数(不考虑其他字符)
范围:包前不包后
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String st = sc.nextLine();
int min=0;
int max=0;
int num=0;
for(int i=0; i<st.length(); i++) {
st.charAt(i); // 就是指定索引处的字符值
if(st.charAt(i)>'a' && st.charAt(i)<='z'){
min++;
}else if(st.charAt(i)>'A' && st.charAt(i)<='Z'){
max++;
}else if(st.charAt(i)>'0' && st.charAt(i)<='9'){
num++;
}
}
System.out.println("大写字母:"+max+"小写字母:"+min+"数字:"+num);
}
例题4.案例 :手机号屏蔽
需求:以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽
最终效果为:156****1234
调用的方法为st.substring(0,3); 取前三值和后四位值
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入手机号:");
String st = sc.nextLine();
String beforenum = st.substring(0,3);
String afterenum = st.substring(7);
System.out.println(beforenum+"****"+afterenum);
}
例题5.需求:替换关键字
键盘录入一个 字符串,如果字符串中包含(TMD),则使用***替换
思路:
1. 键盘录入一个字符串,用 Scanner 实现
2. 替换敏感词
String replace(CharSequence target, CharSequence replacement)
将当前字符串中的target内容,使用replacement进行替换,返回新的字符串
3. 输出结果
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String st = sc.nextLine();
String MSG = st.replace("TMD","***");
System.out.println(MSG);
}
例题6: 字符串录入
需求:以字符串的形式从键盘录入学生信息,
例如:“张三 , 23”
从该字符串中切割出有效数据,封装为Student学生对象
思路:
1.编写Student类,用于封装数据
2.键盘录入一个字符串,用 Scanner 实现
3.根据逗号切割字符串,得到(张三)(23)
String[] split(String regex) :根据传入的字符串作为规则进行切割
将切割后的内容存入字符串数组中,并将字符串数组返回
4.从得到的字符串数组中取出元素内容,通过Student类的有参构造方法封装为对象
5.调用对象getXxx方法,取出数据并打印。
需要获取name和age的值
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String user = sc.nextLine();
String[] split= user.split(",");
String name = split[0];
String age = split[1];
Student su = new Student(name,age);
System.out.println(su.toString());
}
public class Student {
String name;
String age;
public Student() {
}
public Student(String name, String age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
例题7: 对称字符串
需求:键盘接受一个字符串,程序判断出该字符串是否是对称字符串,并在控制台打印是或不是
对称字符串:123321、111
非对称字符串:123123
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String st = sc.nextLine();
StringBuilder sb1 = new StringBuilder(st);
StringBuilder sb2 = sb1.reverse();
String st2 = sb2.toString();
if(st2.equals(st)){
System.out.println("是对称字符串");
}else
System.out.println("不是对称字符串");
例题8: 字符串返回
需求:定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回
调用该方法,并在控制台输出结果。
例如,数组为int[] arr = {1,2,3};
执行方法后的输出结果为:[1, 2, 3]
思路:
1. 定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
2. 定义一个方法,返回值类型 String,参数列表 int[] arr
3. 在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回
4. 调用方法,用一个变量接收结果
5. 输出结果
public static void main(String[] args) {
int[] arr = {1,2,3};
//4. 调用方法,用一个变量接收结果
String printStr = getString(arr);
//5. 输出结果
System.out.println("printStr = " + printStr);
}
public static String getString(int[] arr){
StringBuilder sb= new StringBuilder("[");
for(int i = 0; i < arr.length; i++){
if(i == arr.length-1){
sb.append(arr[i]).append("]");
}else{
sb.append(arr[i]).append(",");
}
}
return sb.toString();
}
}
综合案例!
在控制台上打印输出每一个选项的功能
利用ArrayList集合来做
做两个类 一个student类 一个studentTest类
//student类
package com.itheima.domain;
public class Student {
private String id;
private String name;
private int age;
private String birthday;
public Student() {
}
public Student(String id, String name, int age, String birthday) {
this.id = id;
this.name = name;
this.age = age;
this.birthday = birthday;
}
public String getid() {
return id;
}
public void setid(String sid) {
this.id = sid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return id +"\t\t"+name+"\t"+age+"\t"+birthday+"\t";
}
}
//Test类
package com.itheima.student_test;
import com.itheima.domain.Student;
import java.util.ArrayList;
import java.util.Scanner;
public class StudentTest_01 {
public static void main(String[] args) {
ArrayList<Student> arrayList = new ArrayList<>();
Scanner sc = new Scanner(System.in);
lo :while (true) {
System.out.println("欢迎进入学生管理系统");
System.out.println("-------------------");
System.out.println("1 添加学生信息");
System.out.println("2 删除学生信息");
System.out.println("3 更改学生信息");
System.out.println("4 展示学生信息");
System.out.println("5 退出管理系统");
System.out.println("选择你想进入的选项:");
String s = sc.next();
switch (s) {
case "1":
// 添加学生信息
addStudent(arrayList);
break;
case "2":
//删除学生信息
deleteStudent(arrayList);
break;
case "3":
//更改学生信息
updataStudent(arrayList);
break;
case "4":
//展示学生信息
showStudnet(arrayList);
break;
case "5":
break lo;
default:
System.out.println("重新输入吧");
break;
}
}
}
private static void showStudnet(ArrayList<Student> arrayList) {
System.out.println("学生信息如下:");
System.out.println("学号\t" + "姓名\t" + "年龄\t" + "生日\t");
for (int i = 0; i < arrayList.size(); i++) {
Student student = arrayList.get(i);
System.out.println(student.toString());
}
}
//更改学生信息
private static void updataStudent(ArrayList<Student> arrayList) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个学生id");
String id = sc.next();
int index =getIndex(arrayList,id);
if(index == -1){
System.out.println("输入的id有误,重新输入吧");
}else {
System.out.println("请输入一个学生姓名");
String name = sc.next();
System.out.println("请输入一个学生年龄");
int age = sc.nextInt();
System.out.println("请输入一个学生生日");
String birthday = sc.next();
Student student = arrayList.get(index);
student.setAge(age);
student.setName(name);
student.setid(id);
student.setBirthday(birthday);
System.out.println("修改完成!!!");
}
}
//删除学生信息
private static void deleteStudent(ArrayList<Student> arrayList) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个学生id");
String id = sc.next();
int index = getIndex(arrayList,id);
if (index == -1){
System.out.println("输入的id有误,重新输入吧");
}else{
arrayList.remove(index);
System.out.println("删了!");
}
}
private static void addStudent(ArrayList<Student> arrayList) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个学生id");
String id = sc.next();
System.out.println("请输入一个学生姓名");
String name = sc.next();
System.out.println("请输入一个学生年龄");
int age = sc.nextInt();
System.out.println("请输入一个学生生日");
String birthday = sc.next();
Student student = new Student(id,name,age,birthday);
arrayList.add(student);
System.out.println("创建完成");
}
public static int getIndex(ArrayList<Student> arrayList,String id) {
int index = -1;
for (int i = 0; i < arrayList.size(); i++) {
Student student = arrayList.get(i);
if (id.equals(student.getid())){
index = i;
break;
}
}
return index;
}
}
StringBuilder类
分析如下代码, 执行效率是高还是低呢?
String s = “hello”;
s += “world”;
System.out.println(s);
解释:
如果字符串进行拼接操作, 每次拼接, 都会构建一个新的String对象, 即耗时, 又浪费内存空间. 而这种操作还不可避免,.那有没有一种比较好的方式来解决这个问题呢?
答案是肯定的, 我们可以通过Java提供的StringBuilder类来解决这个问题.
1、概述
StringBuilder类在java.lang包下, 无需导包, 可以直接使用
StringBuilder是一个可变的字符序列, 也叫字符串缓冲区类
我们可以把它看做一个容器, 这里的可变指的是StringBuilder对象中的内容是可变的
String和StringBuilder之间的区别
String: 内容是不可变的
StringBuilder: 内容是可变的
2、构造方法
public StringBuilder()
解释: 创建一个空白可变字符串对象, 它不含有任何内容
public StringBuilder(String str)
解释: 根据字符串的内容, 来创建可变字符串对象
3、示例一: StringBuilder入门
需求
通过上述的两种方式, 创建StringBuilder对象.
在控制台直接打印上述创建好的两个对象, 并观察结果.
参考代码
//案例: 演示StringBuilder入门
/*
概述:
StringBuilder叫: 字符串缓冲区类, 有自带的缓冲区, 可以理解为它是容器,
里边存储的内容是可变的.
StringBuilder中的构造方法:
public StringBuilder(); 空参构造, 创建StringBuilder对象.
public StringBuilder(String str); 带参构造, 创建StringBuilder对象.
可以理解为把 String对象 -> StringBuilder对象.
*/
public class Demo01 {
public static void main(String[] args) {
/*
需求:
1.通过上述的两种方式, 创建StringBuilder对象.
2.在控制台直接打印上述创建好的两个对象, 并观察结果.
*/
//1. 测试空参
StringBuilder sb = new StringBuilder();
System.out.println("sb: " + sb); //打印结果不是地址值, 说明StringBuilder已经重写了Object#toString()方法.
//2. 测试带参, 即: 把String对象 -> StringBuilder对象.
String s1 = "abc";
StringBuilder sb2 = new StringBuilder(s1);
System.out.println("sb2: " + sb2);
}
}
4、添加和反转方法
public StringBuilder append(任意类型)
解释: 添加数据, 并返回对象本身.
public StringBuilder reverse()
解释: 返回相反的字符序列.
需求
通过空参构造创建StringBuilder类的对象sb.
通过append()方法, 往sb对象中添加"hello",然后用sb2对象接收.
打印对象sb和sb2的结果, 并观察.
通过reverse()方法, 来反转上述的内容.
参考代码
//案例: 演示StringBuilder中的方法.
/*
涉及到的StringBuilder中的方法:
public StringBuilder append(任意类型); 添加任意类型的数据, 返回StringBuilder本身.
public StringBuilder reverse(); 反转StringBuilder对象, 返回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);
}
}
5、StringBuilder和String之间的相互转换
StringBuilder转化成String
解释: 可以通过StringBuilder#toString()方法直接实现.
String转成StringBuilder
解释: 通过StringBuilder类的构造方法实现, public StringBuilder(String s)
需求
定义空参不可变StringBuilder对象, 往里边添加完"hello"字符串后, 再将其转成String类型的对象.
将String字符串转成StringBuilder对象, 然后打印.
代码演示
//案例: 演示StringBuilder和String之间的相互转换.
/*
String对象 -> StringBuilder对象
public StringBuilder(String str); 带参构造, 创建StringBuilder对象.
StringBuilder对象 -> String对象
StringBuilder类中的toString()方法
public String toString(); 返回该对象的字符串形式.
*/
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);
}
}
6、案例二: 拼接字符串升级版
需求
定义方法arrayToString(), 把int数组的元素按照指定的格式拼接成一个字符串, 并返回
在main方法中, 调用上述的方法
例如: 数组为int[] arr = {1, 2, 3}, 则拼接后, 结果为: [1, 2, 3]
参考代码
//案例: 拼接字符串.
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();
}
}
7、案例三: 字符串反转
需求
定义方法reverse(), 实现字符串的反转
在main方法中键盘录入一个字符串, 调用上述的方法后, 在控制台输出结果
例如: 键盘录入abc, 输出结果cba
提示: 用for循环, 倒序遍历数组, 然后拼接每一个元素即可
参考代码
//思路: String对象 -> StringBuilder对象 -> 调用StringBuilder对象的reverse()方法 -> 重新换成String对象.
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();
}
}
8、通过帮助文档查看StringBuilder中的方法
public StringBuilder append(任意类型)
解释: 添加数据, 并返回对象本身
public StringBuilder reverse()
解释: 返回相反的字符序列.
public String toString()
解释: 用来将StringBuilder对象, 转成其对应的字符串形式的
关键字(final、 static)
final
final是一个关键字, 表示最终的意思, 可以修饰类, 成员变量, 成员方法.
• 修饰的类: 不能被继承, 但是可以继承其他的类.
• 修饰的变量: 是一个常量, 只能被赋值一次.
• 修饰的方法: 不能被子类重写.
static
概述
static是一个关键字, 表示静态的意思, 可以修饰成员变量, 成员方法.
特点
1.随着类的加载而加载.
2.优先于对象存在.
3.被static修饰的内容, 能被该类下所有的对象共享.
解释: 这也是我们判断是否使用静态关键字的条件.
4.可以通过**类名.**的形式调用.
抽象类
Java中, 一个没有方法体的方法应该定义为抽象方法, 而类中如果有抽象方法, 该类必须定义为抽象类.
abstract
抽象类跟普通类只是多了一个abstract关键字,可以不在子类中重写方法,其他的没什么区别
入门案例
创建抽象类Animal.
在该类中定义抽象方法eat()
参考代码
//抽象的动物类.
public abstract class Animal {
//抽象方法, 吃.
public abstract void{
eat();
}
抽象类的特点
1抽象类和抽象方法必须用abstract关键字修饰.
//抽象类
public abstract class 类名{ }
//抽象方法
public abstract void eat();
2抽象类中不一定有抽象方法, 有抽象方法的类一定是抽象类.
3抽象类不能实例化.
– 那抽象类如何实例化呢?
– 可以通过多态的方式, 创建其子类对象, 来完成抽象类的实例化. 这也叫: 抽象类多态.
4抽象类的子类:
如果是普通类, 则必须重写父抽象类中所有的抽象方法.
如果是抽象类, 则可以不用重写父抽象类中的抽象方法.
抽象类的成员特点
抽象类中可以有变量, 常量, 构造方法, 抽象方法和非抽象方法.
思考: 既然抽象类不能实例化, 那要构造方法有什么用?
答: 用于子类对象访问父类数据前, 对父类数据进行初始化.
接口
1 概述
为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,
简单来说就是某一个类的部分特点显示出来,在类中有的有这些特点,有的没有这些特点.
2 特点
接口用interface关键字修饰.
类和接口之间是实现关系, 用implements关键字表示.
接口不能实例化.
– 那接口如何实例化呢?
– 可以通过多态的方式, 创建其子类对象, 来完成接口的实例化. 这也叫: 接口多态.
接口的子类:
如果是普通类, 则必须重写父接口中所有的抽象方法.
如果是抽象类, 则可以不用重写父接口中的抽象方法.
3 成员特点
接口中有且只能有常量或者抽象方法, 原因是因为:
• 成员变量有默认修饰符: public static final
• 成员方法有默认修饰符: public abstract
注意: 因为接口主要是扩展功能的, 而没有具体存在, 所有接口中是没有构造方法的.
记忆: JDK1.8的时候, 接口中加入了两个新的成员: 静态方法, 默认方法(必须用default修饰).
4 类与接口之间的关系
• 类与类之间: 继承关系, 只能单继承, 不能多继承, 但是可以多层继承.
• 类与接口之间: 实现关系, 可以单实现, 也可以多实现. 还可以在继承一个类的同时实现多个接口.
• 接口与接口之间: 继承关系, 可以单继承, 也可以多继承.
总结:
① 抽象类和接口都是用来抽象具体的对象的,但是接口的抽象级别更高。
② 抽象类可以有具体的方法和属性,接口只能有抽象方法和静态常量。
③ 抽象类主要用来抽象级别,接口主要用来抽象功能。
④ 抽象类中,且不包含任何的实现,派生类必须覆盖它们。接口中所有方法都必须是未实现的。
⑤ 接口方法,访问权限必须是公共的 public。
⑥ 接口内只能有公共方法,不能存在成员变量。
⑦ 接口内只能包含未被实现的方法,也叫抽象方法,但是不能用 abstract 关键字。
⑧ 抽象类的访问速度比接口要快,接口是稍微有点慢,因为它需要时间去寻找在类中实现的方法。
⑨ 抽象类,除了不能被实例化外,与普通 java 类没有任何区别。
⑩ 抽象类可以有 main 方法,接口没有 main 方法。
⑪ 抽象类可以用构造器,接口没有。
⑫ 抽象方法可以有 public、protected 和 default 这些修饰符,接口只能使用默认 public。
⑬ 抽象类,添加新方法可以提供默认的实现,不需要改变原有代码。接口添加新方法,子类必须实现。
⑭ 抽象类的子类用 extends 关键字继承,接口用 implements 来实现。• AddTeacher.java
接口案例1
- 已知有猫类和狗类, 它们都有姓名和年龄, 都要吃饭, 不同的是猫吃鱼, 狗吃肉.
它们都有跑
步的功能, 而且仅仅是跑步, 并无任何区别.
猫独有自己的功能: 抓老鼠catchMouse(), 狗独有自己的功能: 看家lookHome()
部分的猫和狗经过马戏团的训练后, 学会了跳高jump(), 请用所学, 模拟该知识.
//jump接口
package day11_homework_01;
public interface Jump {
void Jump();
}
//Animal类
package day11_homework_01;
public class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(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;
}
public void eat(){
}
public void run(){
System.out.println("跑步!!!!!!");
}
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//Cat类
package day11_homework_01;
public class Cat extends Animal implements Jump{
public Cat() {
}
public Cat(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("吃鱼");
}
public void catchMouse() {
System.out.println("抓老鼠");
}
@Override
public void Jump() {
System.out.println("跳跃");
}
}
//Dog类
package day11_homework_01;
public class Dog extends Animal implements Jump{
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("吃骨头");
}
void lookHome(){
System.out.println("看家");
}
@Override
public void Jump() {
}
}
//Test类
package day11_homework_01;
public class Test {
public static void main(String[] args) {
Cat cat = new Cat("tom",3);
cat.catchMouse();
cat.eat();
cat.Jump();
System.out.println(cat);
Dog Dog = new Dog("大黄", 3) ;
Dog.lookHome();
Dog.eat();
Dog.Jump();
System.out.println(Dog);
}
}
接口案例2
- 已知有乒乓球运动员(PingPangPlayer)和篮球运动员(BasketballPlayer), 乒乓球教练(PingPangCoach)和篮球教练(BasketballCoach).
他们都有姓名和年龄, 都要吃饭, 但是吃的东西不同.
乒乓球教练教如何发球, 篮球教练教如何运球和投篮.
乒乓球运动员学习如何发球, 篮球运动员学习如何运球和投篮.
为了出国交流, 跟乒乓球相关的人员都需要学习英语.
请用所学, 模拟该知识.
//Person类
public class Person {
private String name;
private int age;
public Person() {
}
public Person(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
void eat(){
}
}
//Test类 只测试老师
public class Test {
public static void main(String[] args) {
PingPangCoach ppc = new PingPangCoach("张三丰",23);
ppc.StudyEnglish();
ppc.teachPingPang();
System.out.println(ppc);
ppc.eat();
}
}
//PingPangPlayer类
public class PingPangPlayer extends Person implements English{
public PingPangPlayer() {
}
public PingPangPlayer(String name, int age) {
super(name, age);
}
void PingPangskill(){
System.out.println("我只会发球和接球!");
}
@Override
public void StudyEnglish() {
System.out.println("我不装了,我摊牌了,我是乒乓球界的张无忌");
}
}
//PingPangCoach类
public class PingPangCoach extends Person implements English{
public PingPangCoach() {
}
public PingPangCoach(String name, int age) {
super(name, age);
}
void teachPingPang(){
System.out.println("教发乒乓球!");
}
@Override
public void StudyEnglish() {
System.out.println("我不装了,我摊牌了,我是乒乓球界的张三丰");
}
}
//English接口
public interface English {
void StudyEnglish();
}
//BasketballCoach
public class BasketballCoach extends Person{
void teachBasketball(){
System.out.println("教发篮球!");
}
}
//BasketballPlayer
public class BasketballPlayer extends Person{
public BasketballPlayer() {
}
public BasketballPlayer(String name, int age) {
super(name, age);
}
void Basketballskill(){
System.out.println("我只会运球和投球");
}
}
接口案例3
已知传智播客公司有基础班老师(BasicTeacher)和就业班老师(WorkTeacher), 基础班学生(BasicStudent)和就业班学生(WorkStudent).
他们都有姓名, 年龄, 都要吃饭, 不同的是学生吃牛肉, 老师喝牛肉汤.
老师有自己的额外属性: 工资(salary), 且老师需要讲课(基础班老师讲JavaSE, 就业班老师讲JavaEE, Hadoop, Hive, Scala, Flink, Spark等).
基础班学生学习JavaSE, 就业班学生学习JavaEE, Hadoop, Hive, Scala, Flink, Spark等.
为了扩大就业市场, 跟就业班相关的人员都需要学习英语.
请用所学, 模拟该知识.
//Person
package day11_homework_03;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
void eat(){
}
}
//BasicStudent
package day11_homework_03;
public class BasicStudent extends Person implements Study{
public BasicStudent() {
}
public BasicStudent(String name, int age) {
super(name, age);
}
@Override
void eat() {
System.out.println("我,基础班学生,打钱吃牛肉!");
}
@Override
public void Study() {
System.out.println("我,基础班学生,JavaSE");
}
}
//BasicTeacher
package day11_homework_03;
public class BasicTeacher extends Person implements teach{
public BasicTeacher() {
}
public BasicTeacher(String name, int age) {
super(name, age);
}
@Override
void eat() {
System.out.println("我基础班上海滩文强老师,牛肉汤伺候着!");
}
@Override
public void teach() {
System.out.println("在基础班我教JavaSE!");
}
}
//Study
package day11_homework_03;
public interface Study {
void Study();
}
//teach
package day11_homework_03;
public interface teach {
void teach();
}
//Test
package day11_homework_03;
public class Test {
public static void main(String[] args) {
BasicStudent bs = new BasicStudent("周星宇",22);
bs.eat();
bs.Study();
System.out.println(bs);
System.out.println("--------------");
WorkStudent ws = new WorkStudent("周星宇",22);
ws.eat();
ws.Study();
System.out.println(ws);
}
}
//WorkStudent
package day11_homework_03;
public class WorkStudent extends Person implements Study{
public WorkStudent() {
}
public WorkStudent(String name, int age) {
super(name, age);
}
void eat() {
System.out.println("我,就业班学生,打钱吃牛肉!");
}
@Override
public void Study() {
System.out.println("我,就业班学生,学会了JavaEE, Hadoop, Hive, Scala, Flink, Spark");
}
}
//WorkTeacher
package day11_homework_03;
public class WorkTeacher extends Person implements teach{
public WorkTeacher() {
}
public WorkTeacher(String name, int age) {
super(name, age);
}
@Override
void eat() {
System.out.println("我斧头帮就业办老师,牛肉汤赶紧的!");
}
@Override
public void teach() {
System.out.println("就业办老师我教JavaEE, Hadoop, Hive, Scala, Flink, Spark等");
}
}
包(导包)
1简述层
包(package)就是文件夹, 用来对类进行分类管理的. 例如:
• 学生的增加, 删除, 修改, 查询.
• 老师的增加, 删除, 修改, 查询.
• 其他类的增删改查…
• 基本的划分: 按照模块和功能划分.
• 高级的划分: 就业班做项目的时候你就能看到了.
2格式
package 包名1.包名2.包名3; //多级包之间用.隔开
注意:
package语句必须是程序的第一条可执行的代码.
package语句在一个.java文件中只能有一个.
3 常见分类
• 按照功能分
– com.itheima.add
• AddStudent.java
• AddTeacher.java
• 按照模块分
– com.itheima.student
• AddStudent
• DeleteStudent
– com.itheima.teacher
• AddTeacher
• DeleteTeache
导包
概述
不同包下的类之间的访问,我们发现,每次使用不同包下的类的时候,都需要加包的全路径。比较麻烦。这个时候,java就提供了导包的功能。
格式
import 包名;
import java.util.*; 意思是导入java.util包下所有类, 这样做效率较低, 不推荐使用.
import java.util.Scanner; 意思是导入java.util.Scanner类, 推荐使用. 用谁就导入谁.
权限修饰符
概述
权限修饰符是用来修饰类, 成员变量, 构造方法, 成员方法的, 不同的权限修饰符对应的功能不同. 具体如下:
public | protected | 默认 | private | |
---|---|---|---|---|
同一个类中 | √ | √ | √ | √ |
同一个包中的子类或者其他类 | √ | √ | √ | |
不同包中的子类 | √ | √ | ||
不同包中的其他类(无关类) | √ |
总结
访问权限修饰符的权限从大到小分别是: public > protected > 默认 > private
在实际开发中, 如果没有特殊需求, 则成员变量都用private修饰, 其它都用public修饰.
大白话总结四个访问权限修饰符的作用:
private: 强调的是给自己使用.
默认: 强调的是给同包下的类使用.
protected: 强调的是给子类使用.
public: 强调的是给大家使用.
Object类
他是所有类的父类,所有类都继承于他
成员方法
public String toString();
解释: 返回对象的字符串表示形式(即: 地址值), 无意义, 建议子类重写该方法.
public boolean equals(Object obj);
解释: 比较两个对象是否相等, 默认比较的是地址值, 无意义, 子类一般都会重写该方法.
注意: 实际开发中, 我们认为如果同一个类的两个对象, 各个属性值都相同, 那么它们就是同一个对象.
例如:
//虽然s1和s2对象的地址值不同, 但是它们的属性值都相同, 所以实际开发中我们认为它们是同一个对象.
Student s1 = new Student("刘亦菲", 33);
Student s2 = new Student("刘亦菲", 33);
Arrays类
针对数组进行操作的工具类,提供了吧数组转换成字符串,对数组排序等功能.
工具类解释:
构造方法私有化.
成员方法都是静态的.
成员方法
public static String toString(int[] arr)
解释:吧int类型的数组转换成其对应的字符串形式.
public static void sort(int[] arr)
解释:对给定的int数组,按照元素升序顺序进行排序
e.g.
已知数组int[] arr = {25, 69, 80, 57, 13}.
通过Arrays.sort()方法, 对其升序排列.
打印排序后的结果.
public static void main(String[] args) {
int[] arr = {25, 69, 80, 57, 13};
System.out.println(Arrays.toString(arr));
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
Arrays类的构造方法问题
Arrays类中的成员都是静态的,可以通过类名点形式调用
Arrays类中有一个私有的空参构造方法, 这样做的目的是: 不让用户通过构造方法来创建Arrays类的对象.
包装类
基本类型 | 对应的包装类 |
---|---|
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
byte | Byte |
short | Short |
只有前两个需要特别注意
最常见用法
包装类最常见的用法就是用于该类型对应的基本类型和字符串之间进行相互转换.
Byte用于byte和String之间的相互转换.
Integer用于int和String之间的相互转换.
Double用于double和String之间的相互转换.
int类型 -> String类型
只写最简单的方式实现:
String s1 = 10 + "";
String类型 -> int类型
只写最简单的方式实现:
通过Integer#parseInt()方法来实现.
String s1 = 100;
int num = Integer.parseInt(s1);
4.3.5 示例
需求
已知字符串String s = “91 27 45 38 50”;
请通过代码实现最终输出结果是: “27, 38, 45, 50, 91”
提示
通过String类的split(String regex)方法, 可以按照指定字符切割字符串.
参考代码
public static void main(String[] args) {
String s = "91 27 45 38 50";
String[] str = s.split(" ",5);
int[] arr = new int[5];
for (int i = 0; i < str.length; i++) {
arr[i] = Integer.parseInt(str[i]);
}
Arrays.sort(arr);
System.out.print("\"");
for (int i = 0; i < arr.length; i++) {
if(i == arr.length-1){
System.out.print(arr[i]+"\"");
}
else{
System.out.print(arr[i]+",");
}
}
System.out.println(Arrays.toString(arr)+" ");
}
自动拆装箱
直接把他理解为int类型也是可以的
把基本类型的数据封装成其对应的包装类型, 则称之为自动装箱.
//示例代码
Integer ii = 100; //自动装箱.
把包装类型的对象拆解成其对应的基本类型, 则称之为自动拆箱.
Integer ii = 100;
i1 += 200; //这排水口//自动装箱.
注意: 自动拆装箱都是JDK5的新特性.
Date类
Date类表示特定的瞬间,精确到毫秒. 它是java.util包下的类, 用之前需要先导包.
构造方法
public Date();
解释: 根据当前系统时间, 获取其对应的Date对象.
public Date(long date);
解释: 根据给定的整数, 获取其对应的Date对象.
成员方法
public long getTime()
解释: 获取毫秒值.
public void setTime(long time)
解释: 设置时间, 单位是毫秒值.
SimpleDateFormat类
叫做 : 日期格式化类
概述
SimpleDateFormat 是一个以与语言环境有关的方式来格式化和解析日期的具体类。它允许进行格式化和解析。
格式化(日期 -> 文本), 即: Date -> String
解析(文本 -> 日期), 即: String -> Date
构造方法
public SimpleDateFormat()
默认空参构造,创建SimpleDareFormat类的对象.
public SimpleDateFormat(String pattern)
解释: 根据给定的模板, 创建其对应的SimpleDateFormat类的对象.
成员方法
public final String format(Date date)
解释: 用来格式化日期的.
public Date parse(String source)
解释: 用来解析字符串形式的日期的.
示例一: 格式化日期
需求
把当前时间对象, 按照2020年3月4日 00:00:00格式进行打印.
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
Date date =new Date();
String date1 = sdf.format(date);
System.out.println(date1);
}
示例二: 解析日期字符串
需求
已知字符串String s = “2020年3月4日 00:00:00”;
将上述的字符串转成其对应的Date对象后, 直接打印到控制台上.
参考代码
Calendar类
概述
Calendar类叫: 日历类, 是方便我们操作日期的. 它里边的功能大多数是用来替代java.util.Date类的功能的.
构造方法
Calendar类可以理解为是工具类, 因为它是一个抽象类, 所以外界无法通过new的方式创建本类对象.
问题: 如何创建Calendar类的对象呢?
答案: 通过Calendar#getInstance()方法实现.
4 成员变量
public static final int YEAR
解释: 表示年份.
public static final int MONT
解释: 表示月份.
public static final int DATE
解释: 表示年中的某一天.
public static final int DAYOFMONTH
解释: 表示月中的某一天.
public static final int DAYOFWEEK
解释: 表示星期中的某一天.
成员方法
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)
解释: 修改指定的时间为指定的偏移量, 例如: 往前推2天, 推3个月, 往后推2年.
例题(Obj-Arrays-Date)
1.已知数组int[] arr = {25, 69, 80, 57, 13}, 请编写代码对齐进行升序排序.
即: 排序后结果为: arr = {13, 25, 57, 69, 80};
//两种思路实现.
package Array;
import java.lang.reflect.Array;
import java.util.Arrays;
public class Asc_Desc {
public static void main(String[] args) {
int[] arr = {25, 69, 80, 57, 13};
System.out.println("---------排序前-------------");
System.out.println(Arrays.toString(arr));
System.out.println("-------排序后---------------");
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
System.out.println("______For循环排序_________________");
for (int i = 0; i < arr.length -1 ; i++) {
for (int j = 0; j < arr.length -1 -i; j++) {
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j+1] = arr[j];
arr[j+1] = temp;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
}
}
2.已知字符串String s = “91 27 45 38 50”;
请通过代码实现最终输出结果是: “27, 38, 45, 50, 91”
public class String_to_arr {
public static void main(String[] args) {
String s = "91 27 45 38 50";
String[] s2 = s.split(" ",5);
System.out.print("\"");
for (int i = 0; i < s2.length; i++) {
if(i != s2.length -1){
System.out.print (s2[i]+",");
}else {
System.out.print(s2[i]);
}
}
System.out.print("\"");
}
}
3键盘录入一个纯数字形式的字符串, 中间用, 隔开, 获取该字符串中, 所有的数字之和.
例如:
用户录入: 11, 22, 33, 44, 55
则计算结果为: 165
//DateUtilsDemo测试类
public class String_Sum {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("输入一个纯数字形式的字符串, 中间用, 隔开:");
String s = sc.next();
String[] arr = s.split(",",5);
int[] num = new int[5];
int count =0;
for (int i = 0; i < arr.length; i++) {
num[i] = Integer.parseInt(arr[i]);
System.out.println("num"+i+"=" + num[i]);
count+=num[i];
}
System.out.println(count);
}
}
4.定义工具类DateUtils, 该类有两个方法: date2String(), string2Date(), 分别用来格式化, 解析日期.
在测试类中, 测试上述的两个方法.
package Array;
import javax.xml.crypto.Data;
import java.text.ParseException;
import java.util.Date;
public class DateUtilsDemo {
public static void main(String[] args) throws ParseException {
Date date = new Date();
String time = DateUtils.date2String(date,"yyyy年MM月dd日 HH:mm:ss");
System.out.println(time);
System.out.println("------------------------");
String time1 = "2011/11/11 11:11:11";
Date date1 = DateUtils.string2Date(time1, "yyyy/MM/dd HH:mm:ss");
System.out.println(date1);
}
}
//工具类DateUtils,
package Array;
import javax.xml.crypto.Data;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
//4. 定义工具类DateUtils, 该类有两个方法: date2String(), string2Date(), 分别用来格式化, 解析日期.
// 在测试类中, 测试上述的两个方法.
//格式化(日期 -> 文本), 即: Date -> String
// 解析(文本 -> 日期), 即: String -> Date
public class DateUtils {
//构造方法 私有化 防止别人创建对象使用
private DateUtils(){}
//方法 用static修饰
//将日期按照某一种格式格式化成一个String类型日期
//格式化哪一个日期:调用者
//格式:调用者
public static String date2String(Date date,String pattern){ //格式化日期
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
return sdf.format(date) ;
}
//将一个字符串的格式 根据日期格式转成Date
//哪一个字符串: 调用者决定的
//这个字符串日期是什么格式: 调用者决定
public static Date string2Date(String time, String pattern) throws ParseException {
//解析日期
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
return sdf.parse(time);
}
}
5.提示用户录入年份, 计算该年的2月有多少天, 并将结果打印到控制台上.
//5. 提示用户录入年份, 计算该年的2月有多少天, 并将结果打印到控制台上.
public class printMonth {
public static void main(String[] args) {
//获取某年的2月有多少天
//使用键盘录入某一年
Scanner sc = new Scanner(System.in);
System.out.println("请您输入某一年!");
int year = sc.nextInt();
//设置日期为这一年的3月1号
Calendar calendar = Calendar.getInstance();
calendar.set(year,2,1);
//add方法减去一天 2月最后一天
calendar.add(Calendar.DAY_OF_MONTH,-1);
//然后获取DAY_OF_MONTH
int day = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(day);
}
}
6.提示用户录入他的出生年月日, 计算这个用户一共活了多少天, 并将结果打印到控制台上.
public class birthDemo {
public static void main(String[] args) throws ParseException {
Scanner sc = new Scanner(System.in);
System.out.println("请您按照yyyy-MM-dd的格式输入你的生日!");
String year = sc.next();
//创建时间格式对象并写入格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//创建对象,使用户输入的值可以转换成时间格式
Date date = sdf.parse(year);
//转换成毫秒
long time1 = date.getTime();
System.out.println(time1);
//获取现在的时间转换成毫秒
long time2 = new Date().getTime();
System.out.println(time2);
//算出来的时间是毫秒值
long day = (time2 - time1)/1000/60/60/24;
System.out.println("你已经活了"+day+"了!");
}
}
7.已知字符串"woaiheima,buguanheimahaishibaima,zhaodaogongzuojiushihaoma",将"heima"字符串在上述字符串中出现的次数打印到控制台上
package Array;
//1. 已知字符串"woaiheima,buguanheimahaishibaima,zhaodaogongzuojiushihaoma",
// 将"heima"字符串在上述字符串中出现的次数打印到控制台上.
public class PrintString {
public static void main(String[] args) {
String str = "woaiheima,buguanheimahaishibaima,zhaodaogongzuojiushihaoma";
String sub = "heima";
subStringCount(str,sub);
}
private static void subStringCount(String str, String sub) {
int count = 0;
for (int i = 0; i < str.length() ; i++) {
int j =i;
int k = 0;
while (j<str.length()&&k<sub.length()){
if( str.charAt(j)==sub.charAt(k)){
++j;
++k;
//匹配完
if(k == sub.length() -1){
++count;
}
}else{ //不同就输出
break;
}
}
}
System.out.println(count);
}
}
内部类
类里边还有一个类, 外边那个类叫做外部类, 里边那个类叫做内部类.
e.g.
public class A {
public class B{ //内部类
}
}
分类
1.1 成员内部类
public class A { //外部类
public class B{ //成员内部类
}
}
1.2 局部内部类
public class A{ //外部类
//外部类的成员方法
public void show(){
//局部内部类
class B{
}
}
}
2、匿名内部类
匿名内部类指的就是没有名字的局部内部类
1 前提
必须有一个类(抽象类, 普通类均可), 或者接口
2 格式
new 类名或者接口名() {
//重写类或者接口中所有的抽象方法
};
3 本质
匿名内部类就是一个继承了类或者实现了接口的匿名的子类对象
简单理解:
匿名内部类的本质就是一个子类对象
4 使用场景
当对对象方法(即: 成员方法)仅调用一次的时候
匿名内部类可以作为方法的实参进行传递
//抽象类, 动物类.
public abstract class Animal {
//抽象方法: 表示吃饭.
public abstract void eat();
}
/*
匿名内部类相关介绍:
概述:
匿名内部类就是没有名字的 局部内部类.
局部位置: 方法中, 或者方法的形参列表.
格式:
new 类名或者接口名() {
//重写类或者接口中所有的抽象方法.
};
本质:
匿名内部类就是一个继承了类或者实现了接口的匿名的子类对象.
*/
public class AnimalTest {
public static void main(String[] args) {
//需求: 调用Animal#eat()方法.
//方式一: 传统做法, 搞一个Animal类的子类, 例如: Cat, 然后通过多态实现.
Animal an = new Cat(); //子类名: Cat, 对象名叫: an
an.eat();
System.out.println("-----------------------");
//方式二: 通过匿名对象实现.
/*
匿名对象解释:
概述:
没有名字的对象, 就叫匿名对象.
特点:
用完以后就会变成垃圾对象, 由GC在不确定的时间回收.
*/
//new Cat(): 就是一个继承了Animal类的子类(Cat)的匿名对象.
new Cat().eat(); //子类名: Cat, 对象名叫: ??
System.out.println("-----------------------");
//方式三: 通过匿名内部类实现.
//匿名内部类的本质: 就是一个继承了Animal类的子类的匿名对象.
new Animal() { //子类名: ??, 对象名叫: ??
//重写类或者接口中所有的抽象方法.
@Override
public void eat() {
System.out.println("我是通过匿名内部类的形式创建的 Animal类的子类对象");
}
}.eat();
}
}
注意: 当接口或者抽象类中的抽象方法在3个(含)以下时, 就可以考虑使用匿名内部类的形式来创建对象了
Lambda表达式(和匿名内部类的区别)
可以理解成匿名类的简写形式
实现方式1
匿名内部类的方式
实现方式2
Lambda表达式的方式改进
函数式编程思想
函数式思想尽量忽略面向对象的复杂语法:强调做什么,而不是以什么形式去做
而我们要学习的Lambda表达式就是函数式思想的体现
解释:
形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可 -: ->: 由英文中画线和大于符号组成,固定写法。代表指向动作
代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
组成Lambda表达式的三要素:形式参数,箭头,代码块
Lambda表达式练习1
• 目标
– 无参无返回值抽象方法的练习
• 需求:
– 定义一个接口(Eatable),里面定义一个抽象方法:void eat();
– 定义一个测试类(EatableDemo),在测试类中提供两个方法
• 一个方法是:useEatable(Eatable e)
• 一个方法是主方法,在主方法中调用useEatable方法
//接口
public interface Eatable{
void eat();
}
//实现类
public class EatableImpl implements Eatable {
@Override
public void eat() {
System.out.println("一天一苹果,医生远离我");
}
}
//测试类
public static void main(String[] args) {
//在主方法中调用useEatable方法
Eatable e = new EatableImpl();
useEatable(e);
//匿名内部类
useEatable(new Eatable() {
@Override
public void eat() {
System.out.println("一天一苹果,医生远离我");
}
});
//Lambda表达式
useEatable(() ->{
System.out.println("一天一苹果,医生远离我");
});
}
private static void useEatable(Eatable e) {
e.eat();
}
Lambda表达式练习2
• 目标
有参无返回值抽象方法的练习
• 需求
– 定义一个接口(Flyable),里面定义一个抽象方法:void fly(String s);
– 定义一个测试类(FlyableDemo),在测试类中提供两个方法
• 一个方法是:useFlyable(Flyable f)
• 一个方法是主方法,在主方法中调用useFlyable方法
public static void main(String[] args) {
useFlyable(new Flyable() {
@Override
public void fly(String s) {
System.out.println(s);
System.out.println("飞机自驾游");
}
});
System.out.println("---------");
useFlyable((s) ->{
System.out.println(s);
System.out.println("这是lambda表达式");
});
}
private static void useFlyable(Flyable f){
f.fly("风和日丽,晴空万里");
}
Lambda表达式练习3
• 目标
有参有返回值抽象方法的练习
• 需求
– 定义一个接口(Addable),里面定义一个抽象方法:int add(int x,int y);
– 定义一个测试类(AddableDemo),在测试类中提供两个方法
• 一个方法是:useAddable(Addable a)
• 一个方法是主方法,在主方法中调用useAddable方法
//接口
public interface Addable {
int add(int x,int y);
}
//主方法
public class AddableDemo {
public static void main(String[] args) {
useAddable((int x, int y)-> {
return x + y ;
});
}
private static void useAddable(Addable a) {
int sum = a.add(10,20);
System.out.println(sum);
}
}
Lambda表达式和匿名内部类的区别
所需类型不同
匿名内部类:可以试接口,也可以是抽象类,还可以是具体类
lambda表达式:只能是接口
使用限制不同
如果接口中有且只有一个抽象方法,可以使用lambda表达式,也可以用匿名内部类
如果接口中多余一个抽象方法,只能用匿名内部类,而不能使用lambda表达式
实现原理不同
匿名内部类:变异之后,产生一个单独的.class字节码文件
lambda表达式:变异之后,没有一个单独的.class字节码文件.对应的字节码会在运行的时候动态生成.