封装 encapsulation
package com.hspedu.encapsulation;
public class encapsulation01 {
public static void main(String[] args) {
Person p1 = new Person();
p1.setAge(30);
p1.setName("jack");
p1.setSalary(3000);
System.out.println(p1.info());
}
}
class Person {
public String name;
private int age;
private double salary;
// 快捷键:alt + insert 快速生成getter/setter
public String getName() {
return name;
}
public void setName(String name) {
// 加入对数据的校验
if (name.length() > 2 && name.length() = 1 && age = 2 && name.length() = 20) {
this.balance = balance;
} else {
System.out.println("余额不足,默认为0");
this.balance = 0;
}
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
if (pwd.length() == 6) {
this.pwd = pwd;
} else {
System.out.println("密码不符合要求,必须是6位,默认为000000");
this.pwd = "000000";
}
}
// 显示账号信息
public String info() {
return "账号名:" + name + "n余额:" + balance + "n密码:" + pwd;
}
}
package com.hspedu.encapsulation;
public class AccountTest {
public static void main(String[] args) {
Account account = new Account();
account.setName("jack");
account.setBalance(1000);
account.setPwd("123456");
System.out.println(account.info());
}
}
输出
名字不符合要求,需要在2-4之间 默认为无名 账号名:无名 余额:1000.0 密码:123456
继承 extend
继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends;来声明继承父类即可。
继承的示意图
案例
package com.hspedu.extend_.improve;
// pupil graduate的父类
public class Student {
public String name;
public int age;
private double score;
public void setScore(double score) {
this.score = score;
}
public void showInfo() {
System.out.println("学生名 " + name + " 年龄 " + age + " 成绩 " + score);
}
}
package com.hspedu.extend_.improve;
public class Pupil extends Student {
public void testing() {
System.out.println("小学生 " + name + " 正在考小学数学");
}
}
package com.hspedu.extend_.improve;
public class Graduate extends Student {
public void testing() {
System.out.println("大学生 " + name + " 正在考大学数学");
}
}
package com.hspedu.extend_.improve;
public class Extends01 {
public static void main(String[] args) {
Pupil pupil = new Pupil();
pupil.name = "jack~";
pupil.age = 10;
pupil.testing();
pupil.setScore(99);
pupil.showInfo();
Graduate graduate = new Graduate();
graduate.name = "tom~";
graduate.age = 22;
graduate.testing();
graduate.setScore(88);
graduate.showInfo();
}
}
输出
小学生 jack~ 正在考小学数学 学生名 jack~ 年龄 10 成绩 99.0 大学生 tom~ 正在考大学数学 学生名 tom~ 年龄 22 成绩 88.0
细节
package com.hspedu.extend_;
public class Base {
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
// 无参构造器
public Base() {
System.out.println("Base()...");
}
public void test100() {
System.out.println("test100()...");
}
protected void test200() {
System.out.println("test200()...");
}
void test300() {
System.out.println("test300()...");
}
private void test400() {
System.out.println("test400()...");
}
}
package com.hspedu.extend_;
public class Sub extends Base {
public Sub() {
System.out.println("Sub()...");
}
public void sayOk(){
//非私有的属性和方法可以在子类直接访问
System.out.println(this.n1 + " " + this.n2 + " " + this.n3);
this.test100();
this.test200();
this.test300();
// this.n4;//编译错误
//this.test400();//编译错误
this.callTest400();
int res = this.getN4();
System.out.println("res=" + res);
}
}
package com.hspedu.extend_;
public class ExtendsDetail {
public static void main(String[] args) {
Sub sub = new Sub();
sub.sayOk();
}
}
输出
Base()... Sub()... 100 200 300 test100()... test200()... test300()... test400()... res=400
package com.hspedu.extend_;
public class Base {
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
// 无参构造器
/*
public Base() {
System.out.println("Base()...");
}
*/
public Base(int n1) {
this.n1 = n1;
}
public void test100() {
System.out.println("test100()...");
}
protected void test200() {
System.out.println("test200()...");
}
void test300() {
System.out.println("test300()...");
}
private void test400() {
System.out.println("test400()...");
}
// 父类提供一个公共的方法,这个方法中调用了父类的私有方法
public void callTest400() {
test400();
}
public int getN4() {
return this.n4;
}
}
package com.hspedu.extend_;
public class Sub extends Base {
public Sub() {
super(10);// 调用父类的有参构造器
System.out.println("Sub()...");
}
public void sayOk() {
// 非私有的属性和方法可以在子类直接访问
System.out.println(this.n1 + " " + this.n2 + " " + this.n3);
this.test100();
this.test200();
this.test300();
// this.n4;//编译错误
// this.test400();//编译错误
this.callTest400();
int res = this.getN4();
System.out.println("res=" + res);
}
}
public Sub() {
// this("jack", 100);// 调用本类的有参构造器 报错
super(10);// 调用父类的有参构造器
System.out.println("Sub()...");
}
继承的本质
package com.hspedu.extend_;
public class ExtendsTheroy {
public static void main(String[] args) {
Son son = new Son();
}
}
class Grandpa {
String name = "大头爷爷";
String hobby = "旅游";
public Grandpa() {
System.out.println("Grandpa()...");
}
}
class Father extends Grandpa {
String name = "大头爸爸";
int age = 40;
public Father() {
System.out.println("Father()...");
}
}
class Son extends Father {
String name = "大头儿子";
int age = 10;
public Son() {
System.out.println("Son()...");
}
}
super关键字
在Java中,"super"关键字主要用于访问父类的成员(属性、方法和构造函数)。它可以用于继承关系中,用来引用父类的成员。
以下是在Java中使用"super"关键字的几种常见用法:
class Parent {
protected int num;
public void display() {
System.out.println("Parent class");
}
}
class Child extends Parent {
public void display() {
super.display(); // 调用父类的方法
System.out.println("Child class");
super.num = 10; // 访问父类的属性
}
}
在上面的例子中,子类Child
继承了父类Parent
,并在重写的display
方法中使用super.display()
来调用父类的方法,同时使用super.num
来访问父类的属性。
class Parent {
protected int num;
public Parent(int num) {
this.num = num;
}
}
class Child extends Parent {
public Child(int num) {
super(num); // 调用父类的构造函数
}
}
在上面的例子中,子类Child
继承了父类Parent
,并在自己的构造函数中使用super(num)
来调用父类的构造函数以完成父类属性的初始化。
class Parent1 {
public Parent1() {
System.out.println("Parent1 class");
}
}
class Parent2 extends Parent1 {
public Parent2() {
System.out.println("Parent2 class");
}
}
class Child extends Parent2 {
public Child() {
super(); // 按照指定顺序调用父类的构造函数
}
}
在上面的例子中,子类Child
继承了父类Parent1
和Parent2
,并在自己的构造函数中使用super()
来按照指定顺序调用父类的构造函数。
输出
Parent1 class Parent2 class
总之,"super"关键字是在继承关系中用来访问父类的成员的关键字。它可以用来访问父类的属性、方法和构造函数,并提供了灵活的继承机制。
细节
A->B->C
[前提是父类的属性和方法不能是private]cal() , this.cal()
找方法时,顺序是: (1)先找本类,如果有,则调用
(2)如果没有,则找父类(如果有,并可以调用,则调用)
(3)如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到0bject类
提示:
如果查找方法的过程中,找到了,但是不能访问,则报错 如果查找方法的过程中,没有找到,则提示方法不存在
super.cal()
直接查找父类
super与this比较
方法重写
简单的说:
package com.hspedu.override_;
class Animal {
public void cry() {
System.out.println("动物叫唤...");
}
}
class Dog extends Animal {
// 重写了父类的 cry
public void cry() {
System.out.println("小狗汪汪叫...");
}
}
public class Override01 {
public static void main(String[] args) {
//创建Dog 对象,然后让其 cry
Dog dog = new Dog();
dog.cry();//小狗汪汪叫...
//创建Animal 对象,然后让其 cry
Animal animal = new Animal();
animal.cry();//动物叫唤...
}
}
package com.hspedu.override_;
class Animal {
public Object m1() {
return null;
}
public String m2() {
return null;
}
}
class Dog extends Animal {
//重写了父类的 m1
public String m1() {
return null;
}
// Object 不是 String 的子类,所以不能重写
// public Object m2() {
// return null;
// }
}
public class Override01 {
public static void main(String[] args) {
}
}
重载与重写的区别
多态
引入问题
package com.hspedu.poly;
import com.hspedu.super_.A;
class Food {
private String name;
public Food(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Fish extends Food {
public Fish(String name) {
super(name);
}
}
class Bone extends Food {
public Bone(String name) {
super(name);
}
}
class Animal {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Animal(String name) {
this.name = name;
}
}
class Cat extends Animal {
public Cat(String name) {
super(name);
}
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
}
class Master {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Master(String name) {
this.name = name;
}
// 主人给小狗喂食物 骨头
public void feed(Dog dog, Bone bone) {
System.out.println("主人" + name + "给小狗" + dog.getName() + "喂" + bone.getName());
}
// 主人给小猫喂食物 鱼
public void feed(Cat cat, Fish fish) {
System.out.println("主人" + name + "给小猫" + cat.getName() + "喂" + fish.getName());
}
// 主人给小狗喂食物 鱼
public void feed(Dog dog, Fish fish) {
System.out.println("主人" + name + "给小狗" + dog.getName() + "喂" + fish.getName());
}
// 如果动物很多,食物也很多,那么方法就会很多,代码冗余
}
public class Poly01 {
public static void main(String[] args) {
Master jack = new Master("jack");
Dog dog = new Dog("小白");
Bone bone = new Bone("骨头");
jack.feed(dog, bone);
// 主人给小猫喂食物 鱼
Cat cat = new Cat("小花");
Fish fish = new Fish("鱼");
jack.feed(cat, fish);
// 主人给小狗喂食物 鱼
jack.feed(dog, fish);
}
}
方法或对象具有多种形态。是面向对象的第3三大特征,多态是建立在封装和继承基础之上的。
一个对象的编译类型和运行类型可以不一致
编译类型在定义对象时,就确定了,不能改变 运行类型是可以变化的 编译类型看定义时=号的左边,运行类型看=号的右边
package com.hspedu.poly;
import com.hspedu.super_.A;
class Food {
private String name;
public Food(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Fish extends Food {
public Fish(String name) {
super(name);
}
}
class Bone extends Food {
public Bone(String name) {
super(name);
}
}
class Animal {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Animal(String name) {
this.name = name;
}
}
class Cat extends Animal {
public Cat(String name) {
super(name);
}
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
}
class Master {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Master(String name) {
this.name = name;
}
// // 主人给小狗喂食物 骨头
// public void feed(Dog dog, Bone bone) {
// System.out.println("主人" + name + "给小狗" + dog.getName() + "喂" + bone.getName());
// }
//
// // 主人给小猫喂食物 鱼
// public void feed(Cat cat, Fish fish) {
// System.out.println("主人" + name + "给小猫" + cat.getName() + "喂" + fish.getName());
// }
//
// // 主人给小狗喂食物 鱼
// public void feed(Dog dog, Fish fish) {
// System.out.println("主人" + name + "给小狗" + dog.getName() + "喂" + fish.getName());
// }
// 如果动物很多,食物也很多,那么方法就会很多,代码冗余
// 解决
// 使用多态的方式,只需要一个方法即可
// 1. 使用父类作为形参,这样就可以接收更多的子类对象
// 2. 使用父类作为返回值,这样就可以返回更多的子类对象
// Animal 是父类,可以接收Dog,Cat等子类对象
// Food 是父类,可以接收Bone,Fish等子类对象
public void feed(Animal animal, Food food) {
System.out.println("主人" + name + "给" + animal.getName() + "喂" + food.getName());
}
}
public class Poly01 {
public static void main(String[] args) {
Master jack = new Master("jack");
Dog dog = new Dog("小白");
Bone bone = new Bone("骨头");
jack.feed(dog, bone);
// 主人给小猫喂食物 鱼
Cat cat = new Cat("小花");
Fish fish = new Fish("鱼");
jack.feed(cat, fish);
// 主人给小狗喂食物 鱼
jack.feed(dog, fish);
}
}
细节
向上转型
本质:父类的引用指向了子类的对象 语法:
语法 父类类型 引用名 = new 子类类型();
特点:编译类型看左边,运行类型看右边。 可以调用父类中的所有成员(需遵守访问权限), 不能调用子类中特有成员; 最终运行效果看子类的具体实现!
package com.hspedu.poly.detail;
public class PolyDetail {
public static void main(String[] args) {
// 向上转型();
// 1. 父类的引用指向子类的对象
// 语法 父类类型 引用名 = new 子类类型();
Animal animal = new Cat();
Object obj = new Cat();
// 可以调用父类的方法,不能调用子类 特有的方法 【编译类型决定能不能调用方法】
// cat.catchMouse(); //错误
// 最终执行的是子类的eat方法 【运行类型决定执行哪个方法】
// 规则和方法调用一样
animal.eat();
}
}
向下转型
语法:子类类型
引用名= (子类类型) 父类引用: 只能强转父类的引用,不能强转父类的对象 要求父类的引用必须指向的是当前目标类型的对象 当向下转型后,可以调用子类类型中所有的成员
package com.hspedu.poly.detail;
public class PolyDetail {
public static void main(String[] args) {
// 向上转型();
// 1. 父类的引用指向子类的对象
// 语法 父类类型 引用名 = new 子类类型();
Animal animal = new Cat();
Object obj = new Cat();
// 可以调用父类的方法,不能调用子类特有的方法 【编译类型决定能不能调用方法】
// cat.catchMouse(); //错误
// 最终执行的是子类的eat方法 【运行类型决定执行哪个方法】
// 规则和方法调用一样
animal.eat();
System.out.println("---------------------");
// 向下转型();
// 调用 cat.catchMouse();
// (1) 语法:子类类型 引用名 = (子类类型) 父类引用;
// 编译类型 Cat 运行类型 Cat
Cat cat = (Cat) animal;
cat.catchMouse();
// (2) 要求父类引用必须指向的是当前目标类型的对象
// 比如: Animal animal = new Cat(); 本身指向的就是Cat对象
// Dog dog = (Dog) animal;//编译通过,运行错误
}
}
属性没有重写的说法 直接看编译类型
instanceof
判断对象的类型是否为XX的类型或XX类型的子类型
语法:引用 instanceof 类型 返回boolean
package com.hspedu.poly.detail;
public class PolyDetail02 {
public static void main(String[] args) {
BB bb = new BB();
System.out.println(bb instanceof AA);// true
System.out.println(bb instanceof BB);// true
System.out.println("--------------");
// 编译类型 AA 运行类型 BB
AA aa = new BB();
System.out.println(aa instanceof AA);// true
System.out.println(aa instanceof BB);// true
System.out.println("--------------");
Object obj = new Object();
System.out.println(obj instanceof Object);// true
System.out.println(obj instanceof AA);// false
System.out.println("--------------");
String str = "hello";
System.out.println(str instanceof Object);// true
}
}
class AA {
}
class BB extends AA {
}
java的动态绑定机制
- 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
- 当调用对象属性时,没有动态绑定机制,哪里声明,那里使用
package com.hspedu.poly.dynamic;
public class DynamicBinding {
public static void main(String[] args) {
// 编译类型是A,运行类型是B
A a = new B();
System.out.println(a.sum()); // 210
System.out.println(a.sum1()); // 40
}
}
class A {
public int i = 20;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
public int sum() {
return getI() + 10;
}
public int sum1() {
return i + 20;
}
}
class B extends A {
public int i = 200;
public int getI() {
return i;
}
// public int sum() {
// return getI() + 20;
// }
// public int sum1() {
// return i + 20;
// }
}
多态数组
数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
package com.hspedu.poly.polyarr;
public class PloyArray {
public static void main(String[] args) {
// 多态数组的使用
Person[] person = new Person[5];
person[0] = new Person("jack", 20);
person[1] = new Student("tom", 18, 100);
person[2] = new Student("smith", 19, 50);
person[3] = new Teacher("mary", 30, 5000);
person[4] = new Teacher("scott", 33, 8000);
// 遍历数组,调用每个对象的say方法
for (int i = 0; i < person.length; i++) {
// 编译类型是Person,运行类型是根据情况而定
System.out.println(person[i].say());
// 判断person[i]的运行类型是什么
if (person[i] instanceof Student) {
// 向下转型,调用子类特有的方法
Student student = (Student) person[i];
student.study();
} else if (person[i] instanceof Teacher) {
((Teacher) person[i]).teach();
} else {
System.out.println("不是学生也不是老师");
}
}
}
}
class Person {
private String name;
private int age;
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 String say() {
return "姓名=" + name + " 年龄=" + age;
}
}
class Student extends Person {
private double score;
public Student(String name, int age, double score) {
super(name, age);
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String say() {
return super.say() + " 成绩=" + score;
}
public void study() {
System.out.println("学生" + getName() + "正在学习...");
}
}
class Teacher extends Person {
private double salary;
public Teacher(String name, int age, double salary) {
super(name, age);
this.salary = salary;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String say() {
return super.say() + " 工资=" + salary;
}
public void teach() {
System.out.println("老师" + getName() + "正在授课...");
}
}
多态参数
方法定义的形参类型为父类类型,实参类型允许为子类类型
package com.hspedu.poly.polyparam;
public class Test {
public static void main(String[] args) {
Worker worker = new Worker("ade", 200);
Manager manager = new Manager("tom", 200, 10);
Test test = new Test();
test.showEmpAnnual(worker);
test.showEmpAnnual(manager);
test.testWork(worker);
test.testWork(manager);
}
public void showEmpAnnual(Employee e) {
System.out.println(e.getAnnual());
}
public void testWork(Employee e) {
if (e instanceof Worker) {
((Worker) e).work(); //向下转型
} else if (e instanceof Manager) {
((Manager) e).manage(); //向下转型
}else{
System.out.println("不做处理");
}
}
}
Object类常见API
equals
==
是一个比较运算符
1.既可以判断基本类型,又可以判断引用类型 2.如果判断基本类型,判断的是值是否相等。示例: int i= 10; double d=10.0; 3.如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象
eauals
指示其他某个对象是否与此对象“相等”。
默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。
package com.hspedu.object_;
public class EqualsExercise01 {
public static void main(String[] args) {
Person person1 = new Person("jack", 10, '男');
Person person2 = new Person("jack", 10, '男');
// 默认比较地址 重写后比较每一个属性
System.out.println(person1.equals(person2));
}
}
class Person {
private String name;
private int age;
private char gender;
public boolean equals(Object obj) {
// 判断同一个
if (this == obj) return true;
// 类型的判断是否为 Person
if (obj instanceof Person) {
// 将类型转换,向下转型
Person p = (Person) obj;
return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;
}
return false;
}
public Person(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
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 char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
}
输出
true
hashCode
返回该对象的哈希码值。
package com.hspedu.object_;
public class HashCode_ {
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
A a3 = a1;
System.out.println("a1 " + a1.hashCode());
System.out.println("a3 " + a3.hashCode());
System.out.println("a2 " + a2.hashCode());
}
}
class A {
}
toString
全类名:包名 + 类名
// 源代码
// (1)getCLass().getName()类的全类名(包名+类名)
// (2)Integer.toHexString(hashCode()将对象的hashCode值转成16进制字符串
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
package com.hspedu.object_;
public class ToString_ {
public static void main(String[] args) {
Monster monster = new Monster("小妖怪", "code", 100);
System.out.println(monster.toString());
}
}
class Monster {
private String name;
private String job;
private double sal;
public Monster(String name, String job, double sal) {
this.name = name;
this.job = job;
this.sal = sal;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public double getSal() {
return sal;
}
public void setSal(double sal) {
this.sal = sal;
}
}
输出
com.hspedu.object_.Monster@1b6d3586
package com.hspedu.object_;
public class ToString_ {
public static void main(String[] args) {
Monster monster = new Monster("小妖怪", "code", 100);
System.out.println(monster.toString());
}
}
class Monster {
private String name;
private String job;
private double sal;
public Monster(String name, String job, double sal) {
this.name = name;
this.job = job;
this.sal = sal;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public double getSal() {
return sal;
}
public void setSal(double sal) {
this.sal = sal;
}
@Override
public String toString() { //一般输出对象的属性,也可以自己定制
return "Monster{" +
"name='" + name + ''' +
", job='" + job + ''' +
", sal=" + sal +
'}';
}
}
输出
Monster{name='小妖怪', job='code', sal=100.0}
finalize()
当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。