封装:对象代表什么,就得封装对应的数据,并提供数据对应的行为。
一、多态:对象的多种形态。同类型的对象,表现出的不同形态。
1.多态的表现形式:父类类型 对象名称 = 子类对象;
学生形态 对象
Student s = new Student( );
人的形态 对象
Person p = new Student( );
2.多态的前提:
1)有继承/实现关系。
2)有父类引用指向子类对象。Fu f = new Zi( );
3)有方法的重写。
3.多态的优势:
1)在多态形式下,右边对象可以实现解耦合,便于扩展和维护。
Person p= new Student( );
p.work( ); //业务逻辑发生改变时,后续代码无需修改。
2)★定义方法的时候,使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利。
4.多态的弊端:不能调用子类的特有功能。
1)解决方法:变回子类类型。如果转成其他类类型,会报错。
2)引用数据类型的类型转换,有2种:自动类型转换;强制类型转换。
Person p = new Student(); //自动类型转换
Student s = (Student) p; //强制类型转换
3)强制类型转换,可以转换成真正的子类类型,从而调用子类独有功能。
转换类型与真实对象类型不一致会报错。
转换的时候用instanceof关键字进行判断。
4)代码:
//多态弊端
public class Test {public static void main(String[] args) {//创建对象Animal a = new Dog();//编译看左边,运行看右边a.eat();//多态的弊端//不能调用子类的特有功能//当调用成员方法的时候,编译看左边,运行看右边//在编译的时候会先检查左边的父类中有没有这个方法,如果没有直接报错//a.housekeeping();//多态弊端解决方法:把调用者a再变回子类类型/*int b = 10;byte c = (byte) b;*/Dog d = (Dog) a;d.housekeeping();//细节:转换时候不能转换成随意类型,否则报错/*Cat c = (Cat) a;c.catchMouse();*///实际开发中需要先判断类型是否可以转换/*if (a 是不是 狗){Dog d = (Dog) a;}else if (a 是不是 猫){Cat c = (Cat) a;}*//*if (a instanceof Dog) {Dog dog = (Dog) a;dog.housekeeping();} else if (a instanceof Cat) {Cat cat = (Cat) a;cat.catchMouse();} else {System.out.println("没有这个类型,无法转换");}*///★★★JDK14新特性//先判断a是否为Dog类型,如果是则强转成Dog类型,转换后变量名为dog//如果a不是Dog类型,结果直接为falseif (a instanceof Dog dog) {dog.housekeeping();} else if (a instanceof Cat cat) {cat.catchMouse();} else {System.out.println("没有这个类型,无法转换");}}
}class Animal {public void eat() {System.out.println("动物在吃东西");}
}class Dog extends Animal {@Overridepublic void eat() {System.out.println("狗吃骨头");}public void housekeeping() {System.out.println("狗在看家");}}class Cat extends Animal {@Overridepublic void eat() {System.out.println("猫吃小鱼干");}public void catchMouse() {System.out.println("猫在抓老鼠");}
}
5.多态的应用场景:
1)根据传递对象的不同,调用不同的show方法。
2)代码:
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;}public void show() {System.out.println(name + "," + age);}
}
public class Administrator extends Person {@Overridepublic void show() {System.out.println("管理员的信息为" + getName() + "," + getAge());}
}
public class Student extends Person {@Overridepublic void show() {System.out.println("学生的信息为" + getName() + "," + getAge());}
}
public class Teacher extends Person {@Overridepublic void show() {System.out.println("老师的信息为" + getName() + "," + getAge());}
}
public class Test {public static void main(String[] args) {//创建三个对象,并调用register方法Student s = new Student();s.setName("皓恒");s.setAge(20);Teacher t = new Teacher();t.setName("瑞胤");t.setAge(30);Administrator admin = new Administrator();admin.setName("管理员");admin.setAge(35);register(s);//学生的信息为皓恒,20register(t);//老师的信息为瑞胤,30register(admin);//管理员的信息为管理员,35}//这个方法既能接收老师,又能接收学生,还能接收管理员//只能把参数写成这三个类型的父类public static void register(Person p) {p.show();}
}
6.多态调用成员的特点:
1)变量调用:编译看左边,运行也看左边。
2)方法调用:编译看左边,运行看右边。
3)代码:
public class Test {public static void main(String[] args) {//多态方式创建对象//Fu f = new Zi();Animal a = new Dog();//调用成员变量:编译看左边,运行也看左边//编译看左边:javac编译代码的时候,会看左边的父类中有没有这个变量,如果有编译成功,否则编译失败//运行也看左边:java运行代码的时候,实际获取的就是左边父类中成员变量的值//理解:用a去调用变量和方法,a是Animal类型,默认都会从Animal这个类去找//成员变量:在子类的对象中,会把父类的成员变量也继承下来System.out.println(a.name);//动物//调用成员方法//编译看左边:javac编译代码的时候,会看左边的父类中有没有这个方法,如果有编译成功,否则编译失败//运行看右边:java运行代码的时候,实际上运行的是子类中的方法//成员方法:如果子类对方法进行了重写,在虚方法表里会把父类的方法进行覆盖a.show();//Dog --- show方法}
}class Animal {String name = "动物";public void show() {System.out.println("Animal --- show方法");}
}class Dog extends Animal {String name = "狗";@Overridepublic void show() {System.out.println("Dog --- show方法");}
}class Cat extends Animal {String name = "猫";@Overridepublic void show() {System.out.println("Cat --- show方法");}
}
7.多态的综合练习
public class Animal {/*属性:年龄,颜色行为:eat(String something)(something表示吃的东西)*/private int age;private String color;public Animal() {}public Animal(int age, String color) {this.age = age;this.color = color;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public void eat(String something) {System.out.println("动物在吃" + something);}
}
public class Cat extends Animal {public Cat() {}public Cat(int age, String color) {super(age, color);}/*行为:eat(String something)方法(something表示吃的东西)逮老鼠catchMouse方法(无参数)*/@Overridepublic void eat(String something) {System.out.println(getColor() + getAge() + "岁的猫狼吞虎咽" + something);}public void catchMouse() {System.out.println("猫抓老鼠");}
}
public class Dog extends Animal {/*1.定义狗类行为:eat(String something)(something表示吃的东西)看家housekeeping方法(无参数)*///空参构造//带全部参数的构造public Dog() {}public Dog(int age, String color) {super(age, color);}/*行为:eat(String something)(something表示吃的东西)看家housekeeping方法(无参数)*/@Overridepublic void eat(String something) {System.out.println(getAge() + "岁" + getColor() + "的伯恩山犬懒洋洋地躺在靠椅上吃" + something);}public void housekeeping() {System.out.println("狗在看家");}
}
public class Person {/*属性:姓名,年龄行为:keepPet(Dog dog,String something)方法功能:喂养宠物狗,something表示喂养的东西行为:keepPet(Cat cat,String something)方法功能:喂养宠物猫,something表示喂养的东西生成空参有参构造,set和get方法定义测试类(完成以下打印效果):keepPet(Dog dog,String something)方法打印内容如下:年龄为30岁的饲养员养了一只黑色的3岁的伯恩山犬 // 饲养员的行为3岁黑色的伯恩山犬懒洋洋地躺在靠椅上吃牛肉 //狗的行为keepPet(Cat cat,String something)方法打印内容如下:年龄为35岁的铲屎官养了一只棕色的6岁的猫棕色6岁的猫狼吞虎咽三文鱼罐头*/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;}/*keepPet(Dog dog,String something)方法打印内容如下:年龄为30岁的饲养员养了一只黑色的3岁的伯恩山犬 // 饲养员的行为3岁黑色的伯恩山犬懒洋洋地躺在靠椅上吃牛肉 //狗的行为keepPet(Cat cat,String something)方法打印内容如下:年龄为35岁的铲屎官养了一只棕色的6岁的猫棕色6岁的猫狼吞虎咽三文鱼罐头*//*//饲养狗public void keepPet(Dog dog, String something) {System.out.println("年龄为" + getAge() + "岁的" + getName() +"养了一只" + dog.getColor() + "的" + dog.getAge() + "岁的伯恩山犬");dog.eat(something);}//饲养猫public void keepPet(Cat cat, String something) {System.out.println("年龄为" + getAge() + "岁的" + getName() +"养了一只" + cat.getColor() + "的" + cat.getAge() + "岁的猫");cat.eat(something);}*///生成一个方法,能接收所有的动物//方法的形参,可以写这些类的父类Animalpublic void keepPet(Animal a, String something) {if (a instanceof Dog d) {System.out.println("年龄为" + getAge() + "岁的" + getName() +"养了一只" + d.getColor() + "的" + d.getAge() + "岁的伯恩山犬");d.eat(something);} else if (a instanceof Cat c) {System.out.println("年龄为" + getAge() + "岁的" + getName() +"养了一只" + c.getColor() + "的" + c.getAge() + "岁的猫");c.eat(something);} else {System.out.println("没有这种动物");}}
}
/*根据需求完成代码:
1.定义狗类
属性:
年龄,颜色
行为:
eat(String something)(something表示吃的东西)
看家housekeeping方法(无参数)2.定义猫类
属性:
年龄,颜色
行为:
eat(String something)方法(something表示吃的东西)
逮老鼠catchMouse方法(无参数)3.定义Person类//饲养员
属性:
姓名,年龄
行为:
keepPet(Dog dog,String something)方法
功能:喂养宠物狗,something表示喂养的东西
行为:
keepPet(Cat cat,String something)方法
功能:喂养宠物猫,something表示喂养的东西
生成空参有参构造,set和get方法4.定义测试类(完成以下打印效果):
keepPet(Dog dog,String something)方法打印内容如下:年龄为30岁的饲养员养了一只黑色的3岁的伯恩山犬 // 饲养员的行为3岁黑色的伯恩山犬懒洋洋地躺在靠椅上吃牛肉 //狗的行为
keepPet(Cat cat,String something)方法打印内容如下:年龄为35岁的铲屎官养了一只棕色的6岁的猫棕色6岁的猫狼吞虎咽三文鱼罐头5.思考:1.Dog和Cat都是Animal的子类,以上案例中针对不同的动物,定义了不同的keepPet方法,过于繁琐,能否简化,并体会简化后的好处?2.Dog和Cat虽然都是Animal的子类,但是都有其特有方法,能否想办法在keepPet中调用特有方法?*/
public class Test {public static void main(String[] args) {/*//创建对象并调用方法Person p1 = new Person("饲养员", 30);Dog d = new Dog(3, "黑色");p1.keepPet(d, "牛肉");Person p2 = new Person("铲屎官", 35);Cat c = new Cat(6, "棕色");p2.keepPet(c, "三文鱼罐头");*///创建饲养员的对象Person p = new Person("饲养员", 30);Dog d = new Dog(3, "黑色");Cat c = new Cat(6, "棕色");p.keepPet(d, "牛肉");p.keepPet(c, "三文鱼罐头");}
}
二、包
1.作用:
1)包就是文件夹。
2)用来管理各种不同功能的Java类,方便后期代码维护。
2.包名的规则:公司域名反写+包的作用。
需要全部英文小写,见名知意。com.company.domain
package com.company.domain
public class Student{
私有化成员变量
构造方法
成员方法
}
3.全类名/全限定名:包名+类名
com.company.domain.Student
4.使用其他类的规则
1)推演:
使用其他类时,需要使用全类名。
public class Test {public static void main(String[] args) {com.company.domain.Student s = new com.company.domain.Student();}
}
//导包
import com.company.domain.Student;public class Test {public static void main(String[] args) {Student s = new Student();}
}
2)使用同一个包中的类时,不需要导包。
3)使用java.lang包中的类时,不需要导包。
4)其他情况都需要导包。
5)如果同时使用两个包中的同名类,需要用全类名。
三、final:最终的,不可被改变的。
1.final修饰方法(了解):表明该方法是最终方法,不能被重写。
应用:不想被改变的规则方法。
2.final修饰类(了解):表明该类是最终类,不能被继承。
3.final修饰变量(掌握):叫做常量,只能被赋值一次。
1)常量:实际开发中,常量一般作为系统的配置信息,方便维护,提高可读性。
2)常量的命名规范:
单个单词:全部大写。
多个单词:全部大写,单词之间用下划线隔开。
3)★★★细节:
final修饰的变量是基本数据类型:变量存储的数据值不能发生改变。
final修饰的变量是引用数据类型:变量存储的地址值不能发生改变,对象内部的属性值可以改变。
4)核心:
常量记录的数据是不能发生改变的。
5)字符串是不可变的(private,final)。
6)常量的练习:
将学生管理系统中用户的操作改写为常量的形式。
Project Structure–Modules–Import Module–包里的iml配置文件
代码:
import java.util.ArrayList;
import java.util.Scanner;public class StudentSystem {private static final String ADD_STUDENT = "1";private static final String DELETE_STUDENT = "2";private static final String UPDATE_STUDENT = "3";private static final String QUERY_STUDENT = "4";private static final String EXIT = "5";public static void startStudentSystem() {ArrayList<Student> list = new ArrayList<>();loop:while (true) {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("请输入您的选择:");Scanner sc = new Scanner(System.in);String choose = sc.next();switch (choose) {case ADD_STUDENT -> addStudent(list);case DELETE_STUDENT -> deleteStudent(list);case UPDATE_STUDENT -> updateStudent(list);case QUERY_STUDENT -> queryStudent(list);case EXIT -> {System.out.println("退出");System.exit(0);}default -> System.out.println("没有这个选项");}}}
}
四、权限修饰符
1.用来控制一个成员能够被访问的范围。
2.可以修饰成员变量,方法,构造方法,内部类。
3.有四种,作用范围由小到大(private < 空着不写(缺省/默认) < protected < public)
4.权限修饰符的使用规则:
1)实际开发中,一般只用private和public。
成员变量私有。方法公开。
2)特例:如果方法中的代码是抽取其他方法中的共性代码,这个方法一般也私有。
五、代码块
1.局部代码块(淘汰)
1)写在方法里的单独的大括号。节约内存。
2)提前结束变量的生命周期(已淘汰)。
public class Test {public static void main(String[] args) {//局部代码块(节约内存,淘汰){int a = 10;}//当代码执行到这里时,变量a就从内存中消失了System.out.println(a);}
}
2.构造代码块(逐渐淘汰)
1)写在成员位置的代码块。
2)作用:可以把多个构造方法中重复的代码抽取出来(不够灵活)。
3)执行时机:我们在创建本类对象的时候会先执行构造代码块再执行构造方法。
3.静态代码块(掌握)
1)格式:static{}
2)特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发,只执行一次。
3)使用场景:在类加载的时候,做一些数据初始化的时候使用(重点)。
4.代码:
public class Student {private String name;private int age;//执行时机://随着类的加载而加载的,并且只执行一次static {System.out.println("静态代码块执行了");}/* //构造代码块{System.out.println("开始创建对象了");}public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}*///构造方法里有重复
/* //第一种方法public Student() {//调用本类其他构造this(null,0);}public Student(String name, int age) {System.out.println("开始创建对象了");this.name = name;this.age = 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;}
}
import java.util.ArrayList;
import java.util.Scanner;public class App {//静态代码块,初始化static ArrayList<User> list = new ArrayList<>();static {//添加一些用户信息list.add("川研", "123", "312123505009081234", "12345677890");}public static void main(String[] args) {Scanner sc = new Scanner(System.in);while (true) {System.out.println("欢迎来到学生管理系统");System.out.println("请选择操作:1.登录 2.注册 3.忘记密码");String choose = sc.next();switch (choose) {case "1" -> login(list);case "2" -> register(list);case "3" -> forgetPassword(list);case "4" -> {System.out.println("谢谢使用,再见");System.exit(0);}//大括号不能省略default -> System.out.println("没有这个选项");}}}
}