一、继承性

1.继承性的理解

四:面向对象(中)(2022.4.2 施工完毕✅) - 图1

2.继承性的使用

  1. /**
  2. * 继承性格式:class B extends A{}
  3. * A:父类、超类、基类、superclass
  4. * B:子类、派生类、subclass
  5. * extends:延展、扩展
  6. * 子类可以在拥有父类的功能后,再进行功能的扩展:一代更比一代强!
  7. */
  8. public class Test {
  9. public static void main(String[] args) {
  10. Student s = new Student();//实例化学生类
  11. s.name = "小明"; //子类调用(拥有)父类的属性
  12. s.eat(); //子类调用(拥有)父类的方法
  13. }
  14. }
  15. //简简单单定义一个人类
  16. class Person{
  17. String name;
  18. int age;
  19. public void eat(){
  20. System.out.println("吃饭");
  21. }
  22. public void sleep(){
  23. System.out.println("睡觉");
  24. }
  25. }
  26. //学生也是人的一种,故尝试继承Person类
  27. class Student extends Person{
  28. String major;
  29. }

3.继承性的规定

  1. /**
  2. * 继承性的规定:
  3. * 1.一个父类可以拥有多个子类。
  4. * 2.单继承性:一个子类类不可以拥有多个父类。
  5. * 3.支持多层继承,分别称为直接父类、间接父类...
  6. */
  7. public class Test {
  8. public static void main(String[] args) {
  9. Student s = new Student();
  10. //以下为多层继承
  11. s.breath();
  12. s.say();
  13. s.book();
  14. }
  15. }
  16. //简简单单定义一个生物类
  17. class Creature{
  18. int age;
  19. public void breath(){
  20. System.out.println("呼吸");
  21. }
  22. }
  23. //定一个人类
  24. class Person extends Creature{
  25. String name;
  26. public void say(){
  27. System.out.println("说话");
  28. }
  29. }
  30. //定一个学生类
  31. class Student extends Person{
  32. String school;
  33. public void book(){
  34. System.out.println("看书");
  35. }
  36. }

4.Object类的简单理解

image.png
引入:我们在Creature类中只定义了breath()方法为什么会有这么多方法捏?

  1. /**
  2. * Object类:
  3. * 1.如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类
  4. * 2.所有定义的类都会直接或间接的继承Object类(Object生万物)
  5. */
  6. public class Test {
  7. public static void main(String[] args) {
  8. Creature c = new Creature();
  9. //这个方法并没有定义,但却提供了
  10. c.equals(obj);
  11. }
  12. }
  13. //简简单单定义一个生物类
  14. class Creature{
  15. int age;
  16. public void breath(){
  17. System.out.println("呼吸");
  18. }
  19. }

5.继承性的练习

  1. /**
  2. * 在CylinderTest类中创建Cylinder类的对象,设置圆柱的底面半径和高,并输出圆柱的体积。
  3. * 分开:圆柱类继承底面圆类
  4. */
  5. public class Test {
  6. public static void main(String[] args) {
  7. Cylinder c = new Cylinder();
  8. c.setRadius(3.0);
  9. c.setHeight(3.0);
  10. double volume = c.getVolume();
  11. System.out.println(volume);
  12. }
  13. }
  14. //定义圆类
  15. class Circle{
  16. private double radius;
  17. public void setRadius(double radius) {
  18. this.radius = radius;
  19. }
  20. public double getRadius() {
  21. return radius;
  22. }
  23. public double getArea(){
  24. return Math.PI * radius * radius;
  25. }
  26. }
  27. //定义圆柱类
  28. class Cylinder extends Circle{
  29. private double height;
  30. public void setHeight(double height) {
  31. this.height = height;
  32. }
  33. public double getHeight() {
  34. return height;
  35. }
  36. public double getVolume(){
  37. return getArea() * getHeight();
  38. }
  39. }

二、方法重写

1.方法重写的理解及使用

  1. /**
  2. * 方法重写(overwrite):
  3. * 1.重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作
  4. * 2.应用:当发现父类的方法有点不太符合子类功能可以重写
  5. * 3.子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
  6. * >特殊情况:子类不能重写父类中声明为private权限的方法
  7. * 4.返回值类型:
  8. * >父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
  9. * >父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子
  10. * >父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的
  11. */
  12. public class Test {
  13. public static void main(String[] args) {
  14. Student s = new Student();
  15. s.eat(); // 仍是子类方法
  16. s.eat("苹果"); // 仍是父类方法
  17. s.sleep(); // 覆盖父类方法
  18. }
  19. }
  20. //简简单单定义一个人类
  21. class Person{
  22. String name;
  23. int age;
  24. public Person(){
  25. }
  26. public Person(String name,int age){
  27. this.name = name;
  28. this.age = age;
  29. }
  30. public void eat(String fruit){
  31. System.out.println("人吃" + fruit);
  32. }
  33. public void sleep(){
  34. System.out.println("睡觉");
  35. }
  36. }
  37. //定义学生类
  38. class Student extends Person{
  39. String major;
  40. public Student(){
  41. }
  42. public void eat(){ //此方法并没有重写父类的eat方法,因为参数不同
  43. System.out.println("学生吃饭");
  44. }
  45. public void sleep(){ // 此方法覆盖父类方法,因为方法名和参数相同
  46. System.out.println("学生睡觉");
  47. }
  48. }

2.方法重写的练习

(1)、方法重载和方法重写的区别
1、方法重载(overload):
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
2、方法重写(overwrite):
子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作。
(2)、定义的类Kid,在Kid中重新定义employeed()方法覆盖父类ManKind中定义的employeed()方法,输出”Kid should study and no job.”

  1. /**
  2. * 题解
  3. */
  4. public class Test {
  5. public static void main(String[] args) {
  6. Kid k = new Kid();
  7. k.employeed();
  8. }
  9. }
  10. //定义一个人类
  11. class Mankind{
  12. String name;
  13. int age;
  14. public Mankind(){
  15. }
  16. public Mankind(String name,int age){
  17. this.name = name;
  18. this.age = age;
  19. }
  20. public void employeed(){
  21. System.out.println("人类应该干活");
  22. }
  23. }
  24. //学生也是人的一种,故尝试继承Person类
  25. class Kid extends Mankind{
  26. String school;
  27. public Kid(){
  28. }
  29. public void employeed(){ // 此方法覆盖父类方法,因为方法名和参数相同
  30. System.out.println("Kid should study and no job.");
  31. }
  32. }

三、super关键字

1.super调用属性、方法及构造器

  1. /**
  2. * 3.super调用属性和方法
  3. * 3.1我们可以在子类的方法或构造器中。通过使用"super.属性"或"super.方法"的方式,显式的调用父类中声明的属性或方法。但是,通常情况下,我们习惯省略"super."
  4. * 3.2特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的是父类中声明的属性。
  5. * 3.3特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法。
  6. * 4.super调用构造器
  7. * 4.1 我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器
  8. * 4.2 "super(形参列表)"的使用,必须声明在子类构造器的首行!
  9. * 4.3 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一,不能同时出现。
  10. * 4.4 在构造器的首行,既没有显式的声明"this(形参列表)"或"super(形参列表)",则默认的调用的是父类中的空参构造器。super()
  11. * 4.5 在类的多个构造器中,至少有一个类的构造器使用了"super(形参列表)",调用父类中的构造器。
  12. */
  13. public class Test {
  14. public static void main(String[] args) {
  15. Student s = new Student(); // 调用了父类空参构造器
  16. s.show();
  17. }
  18. }
  19. //简简单单定义一个人类
  20. class Person {
  21. String name;
  22. int age;
  23. int id = 1001; //身份证号
  24. public Person(){
  25. System.out.println("一会子类得调用我");
  26. }
  27. public Person(String name){
  28. this.name = name;
  29. }
  30. public Person(String name,int age){
  31. this(name); // 调用前面的构造器
  32. this.age = age;
  33. }
  34. public void eat(){
  35. System.out.println("人,吃饭");
  36. }
  37. }
  38. class Student extends Person{
  39. String major;
  40. int id = 1002; // 学号
  41. public Student(){
  42. //看似空构造器其实隐含着super();调用父类空参构造器
  43. }
  44. public void eat(){
  45. System.out.println("学生吃健康的");
  46. }
  47. public void show(){
  48. System.out.println("id = " + id); // 子类
  49. System.out.println("id = " + super.id); // 调用父类属性
  50. super.eat(); //调用父类方法
  51. }
  52. }

2.子类对象的实例化过程

image.png
image.png

  1. /*
  2. * 子类对象实例化的全过程
  3. *
  4. * 1.从结果上看:
  5. * 子类继承父类以后,就获取了父类中声明的属性或方法。
  6. * 创建子类的对象中,在堆空间中,就会加载所有父类中声明的属性。
  7. *
  8. * 2.从过程上看:
  9. * 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类构造器,
  10. * 直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类结构,所以才可以看到内存中有
  11. * 父类中的结构,子类对象可以考虑进行调用。
  12. *
  13. * 明确:虽然创建子类对象时,调用了父类的构造器,但自始至终就创建过一个对象,即为new的子类对象。
  14. */
  15. public class InstanceTest {
  16. }

3.继承性和super的练习

Account类

  1. /*
  2. * 写一个名为Account的类模拟账户。该类的属性和方法如下图所示。
  3. * 该类包括的属性:账号id,余额balance,年利率annualInterestRate;
  4. * 包含的方法:访问器方法(getter和setter方法),
  5. * 返回月利率的方法getMonthlyInterest(),
  6. * 取款方法withdraw(),存款方法deposit()。
  7. *
  8. */
  9. public class Account {
  10. private int id; //账号
  11. private double balance; //余额
  12. private double annualInterestRate; //年利率
  13. public Account(int id, double balance, double annualInterestRate) {
  14. super();
  15. this.id = id;
  16. this.balance = balance;
  17. this.annualInterestRate = annualInterestRate;
  18. }
  19. public int getId() {
  20. return id;
  21. }
  22. public void setId(int id) {
  23. this.id = id;
  24. }
  25. public double getBalance() {
  26. return balance;
  27. }
  28. public void setBalance(double balance) {
  29. this.balance = balance;
  30. }
  31. public double getAnnualInterestRate() {
  32. return annualInterestRate;
  33. }
  34. public void setAnnualInterestRate(double annualInterestRate) {
  35. this.annualInterestRate = annualInterestRate;
  36. }
  37. public double getMonthlyInterest(){ //返回月利率的方法
  38. return annualInterestRate / 12;
  39. }
  40. public void withdraw (double amount){ //取款方法
  41. if(balance >= amount){
  42. balance -= amount;
  43. return;
  44. }
  45. System.out.println("余额不足");
  46. }
  47. public void deposit (double amount){ //存款方法
  48. if(amount > 0){
  49. balance += amount;
  50. }
  51. }
  52. }

AccountTest类

  1. /*
  2. * 写一个用户程序测试Account类。在用户程序中,
  3. * 创建一个账号为1122、余额为20000、年利率4.5%的Account对象。
  4. * 使用withdraw方法提款30000元,并打印余额。再使用withdraw方法提款2500元,
  5. * 使用deposit方法存款3000元,然后打印余额和月利率。
  6. */
  7. public class AccountTest {
  8. public static void main(String[] args) {
  9. Account acct = new Account(1122,20000,0.045);
  10. acct.withdraw(30000);
  11. System.out.println("你的账户余额为:" + acct.getBalance());
  12. acct.withdraw(2500);
  13. System.out.println("你的账户余额为:" + acct.getBalance());
  14. acct.deposit(3000);
  15. System.out.println("你的账户余额为:" + acct.getBalance());
  16. System.out.println("月利率为: " + (acct.getAnnualInterestRate() * 100) + "%");
  17. }
  18. }

CheckAccount类

  1. /*
  2. * 创建Account类的一个子类CheckAccount代表可透支的账户,该账户中定义一个属性overdraft代表可透支限额。
  3. * 在CheckAccount类中重写withdraw方法,其算法如下:
  4. * 如果(取款金额<账户余额),
  5. * 可直接取款
  6. * 如果(取款金额>账户余额),
  7. * 计算需要透支的额度
  8. * 判断可透支额overdraft是否足够支付本次透支需要,如果可以
  9. * 将账户余额修改为0,冲减可透支金额
  10. * 如果不可以
  11. * 提示用户超过可透支额的限额
  12. *
  13. */
  14. public class CheckAccount extends Account{
  15. private double overdraft; //代表可透支限额
  16. public CheckAccount(int id, double balance, double annualInterestRate,double overdraft){
  17. super(id, balance, annualInterestRate);
  18. this.overdraft = overdraft;
  19. }
  20. public double getOverdraft() {
  21. return overdraft;
  22. }
  23. public void setOverdraft(double overdraft) {
  24. this.overdraft = overdraft;
  25. }
  26. @Override
  27. public void withdraw(double amount) {
  28. if(getBalance() >= amount){ //余额足够消费
  29. //方式一
  30. // setBalance(getBalance() - amount);
  31. //方式二
  32. super.withdraw(amount);
  33. }else if(overdraft >= amount - getBalance()){ //余额不够
  34. overdraft -= (amount - getBalance());
  35. // setBalance(0);
  36. //或
  37. super.withdraw(getBalance());
  38. }else{ //超过可透支限额
  39. System.out.println("超过可透支限额!");
  40. }
  41. }
  42. }

CheckAccountTest类

  1. /*
  2. * 写一个用户程序测试CheckAccount类。在用户程序中,
  3. * 创建一个账号为1122、余额为20000、年利率4.5%,
  4. * 可透支限额为5000元的CheckAccount对象。
  5. * 使用withdraw方法提款5000元,并打印账户余额和可透支额。
  6. * 再使用withdraw方法提款18000元,并打印账户余额和可透支额。
  7. * 再使用withdraw方法提款3000元,并打印账户余额和可透支额。
  8. *
  9. */
  10. public class CheckAccountTest {
  11. public static void main(String[] args) {
  12. CheckAccount cat = new CheckAccount(1122,20000,0.045,5000);
  13. cat.withdraw(5000);
  14. System.out.println("您的账户余额为: " + cat.getBalance());
  15. System.out.println("您的可透支额度为: " + cat.getOverdraft());
  16. cat.withdraw(18000);
  17. System.out.println("您的账户余额为: " + cat.getBalance());
  18. System.out.println("您的可透支额度为: " + cat.getOverdraft());
  19. cat.withdraw(3000);
  20. System.out.println("您的账户余额为: " + cat.getBalance());
  21. System.out.println("您的可透支额度为: " + cat.getOverdraft());
  22. }
  23. }

四、多态性

1.多态性的使用

  1. /**
  2. * 多态性:
  3. * 1.理解多态性:可以理解为一个事物的多种形态。
  4. * 2.何为多态性:对象的多态性:父类的引用指向子类的对象
  5. * 3.多态的使用:虚拟方法调用
  6. * 有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
  7. * 总结:编译,看左边;运行,看右边。
  8. */
  9. public class Test {
  10. public static void main(String[] args) {
  11. Person p1 = new Person();
  12. p1.eat();
  13. Man m1 = new Man();
  14. m1.eat();
  15. m1.age = 25;
  16. m1.earnMoney();
  17. //对象的多态性:父类的引用指向子类的对象
  18. //Person p2为父类 new Man()为子类的对象
  19. Person p2 = new Man();
  20. //Person w1 = new Woman(); 同理
  21. //多态的使用:当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法---虚拟方法调用
  22. p2.eat();//输出为Man类中的同名方法
  23. //p2.earnMoney();此方法并不能调用
  24. //3.多态的使用:虚拟方法调用,有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。总结:编译,看左边;运行,看右边。
  25. }
  26. }
  27. //简简单单定义一个人类
  28. class Person {
  29. String name;
  30. int age;
  31. public void eat(){
  32. System.out.println("人,吃饭");
  33. }
  34. }
  35. class Man extends Person{
  36. boolean isSmoking;
  37. public void earnMoney(){
  38. System.out.println("挣钱");
  39. }
  40. public void eat(){
  41. System.out.println("男人吃饭长肌肉");
  42. }
  43. public void walk(){
  44. System.out.println("男人走路");
  45. }
  46. }
  47. class Woman extends Person{
  48. boolean isBeauy;
  49. public void goShopping(){
  50. System.out.println("女人购物");
  51. }
  52. public void eat(){
  53. System.out.println("女人吃饭");
  54. }
  55. public void walk(){
  56. System.out.println("女人窈窕走路");
  57. }
  58. }

特别声明:多态性只使用于方法,不适用属性

2.多态性使用举例

  1. /**
  2. * 多态性:
  3. * 1.理解多态性:可以理解为一个事物的多种形态。
  4. * 2.何为多态性:对象的多态性:父类的引用指向子类的对象
  5. * 3.多态的使用:虚拟方法调用
  6. * 有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
  7. * 总结:编译,看左边;运行,看右边。
  8. */
  9. public class Test {
  10. public static void main(String[] args) {
  11. Test t = new Test();
  12. Animal a1 = new Dog();
  13. t.func(a1);
  14. }
  15. public void func(Animal animal){ //此处声明的是一个Animal对象但是new的是一个Dog
  16. animal.eat();
  17. animal.shout();
  18. }
  19. //如果没有多态会发生以下这种情况重载无数方法...
  20. public void func(Dog dog){
  21. }
  22. public void func(Cat cat){
  23. }
  24. }
  25. //举例一
  26. class Animal{
  27. public void shout(){
  28. System.out.println("动物叫了");
  29. }
  30. public void eat(){
  31. System.out.println("动物吃饭");
  32. }
  33. }
  34. class Dog extends Animal{
  35. public void eat(){
  36. System.out.println("狗吃骨头");
  37. }
  38. public void shout(){
  39. System.out.println("汪汪汪");
  40. }
  41. }
  42. class Cat extends Animal{
  43. public void eat(){
  44. System.out.println("猫吃鱼");
  45. }
  46. public void shout(){
  47. System.out.println("喵喵喵");
  48. }
  49. }
  50. //举例二
  51. class Order{
  52. public void method(Object obj){
  53. //Object类传入所有对象,通用性巨大
  54. }
  55. }

3.虚拟方法调用

image.png
多态是编译时行为还是运行时行为?

4.向下转型的理解+instanceof操作符+练习

x instanceof A:检验x是否为类A的对象,返回值为boolean型。

  1. /**
  2. * 看下面的注释
  3. */
  4. public class Test {
  5. public static void main(String[] args) {
  6. //声明生物父类但new一个人类子类
  7. Creature c1 = new Human();
  8. //发现子类特有的方法无法调用
  9. c1.say();//此方法无法使用
  10. //这里使用向下转型:也即使用强制转换符
  11. Human h1 = (Human)c1;
  12. h1.say();//此时子类特有方法可以使用了
  13. //因为new的是一个Human对象,所以以下方法无法使用并抛出异常
  14. Monkey m1 = (Monkey)c1;
  15. m1.eat();//此方法无法使用
  16. //为了避免上述异常问题引入instanceof关键字:x instanceof A:检验x是否为类A的对象,返回值为boolean型
  17. if(c1 instanceof Monkey){
  18. System.out.println("是猴子");
  19. }
  20. if(c1 instanceof Human){
  21. System.out.println("是人类");
  22. }
  23. //根据继承性,下面的表达式返回的依然是True
  24. if(c1 instanceof Creature){
  25. System.out.println("是人类");
  26. }
  27. //练习
  28. //问题一:编译时通过,运行时不通过
  29. Creature c2 = new Human();
  30. Monkey m2 = (Monkey)c2;//编译不报错但是运行时会抛出异常,这时候就要加个instanceof了
  31. //问题二:编译通过,运行也通过
  32. Object o1 = new Human();
  33. Creature c3 = (Creature)o1;
  34. //问题三:编译不通过
  35. Human h2 = new Monkey();//很明显这两个类是平行关系...编译直接标红Type mismatch(类型不匹配)
  36. }
  37. }
  38. class Creature{
  39. int age;
  40. public void not(){
  41. System.out.println("生物大类没啥方法好定义的");
  42. }
  43. }
  44. class Human extends Creature{
  45. String name;
  46. public void say(){
  47. System.out.println("人会说话");
  48. }
  49. }
  50. class Monkey extends Creature{
  51. boolean isBanana;
  52. public void eat(){
  53. System.out.println("猴子吃香蕉");
  54. }
  55. }

image.png

5.多态性的练习

练习一

  1. /**
  2. * 练习一:子类继承父类
  3. *
  4. * 1.若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,
  5. * 系统将不可能把父类里的方法转移到子类中。
  6. *
  7. * 2.对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,
  8. * 这个实例变量依然不可能覆盖父类中定义的实例变量
  9. */
  10. public class FieldMethodTest {
  11. public static void main(String[] args){
  12. Sub s= new Sub();
  13. System.out.println(s.count);//重名属性直接在子类中可以找到为:20
  14. s.display();//在子类中已重写的父类方法,故输出20
  15. //把 子类对象s 赋给 父类引用b
  16. Base b = s;
  17. //==:对于引用数据类型来讲,比较的是两个引用数据类型变量的地址值是否一样。
  18. System.out.println(b == s); //true
  19. System.out.println(b.count);//此为多态性,因为引用为父类所以输出父类的属性:10
  20. b.display();//此为多态性,虽然引用为父类,但是子类中重写了该方法,输出为:20
  21. }
  22. }
  23. class Base {
  24. int count= 10;
  25. public void display() {
  26. System.out.println(this.count);
  27. }
  28. }
  29. class Sub extends Base {
  30. int count= 20;
  31. public void display() {
  32. System.out.println(this.count);
  33. }
  34. }

练习二

  1. /**
  2. * 练习二:
  3. * 建立InstanceTest 类,在类中定义方法method(Person e);
  4. *
  5. * 在method中:
  6. * (1)根据e的类型调用相应类的getInfo()方法。
  7. * (2)根据e的类型执行:
  8. * 如果e为Person类的对象,输出:“a person”;
  9. * 如果e为Student类的对象,输出:“a student”
  10. * 如果e为Graduate类的对象,输出:“a graduated student”
  11. * “a student” “a person”
  12. */
  13. public class InstanceTest {
  14. //这里的形参传入体现了多态性
  15. public void method(Person e) {
  16. //虚拟方法调用
  17. e.getInfo();
  18. //instanceof关键字使用
  19. //方式一
  20. if(e instanceof Graduate){
  21. System.out.println("a graduated student");
  22. }
  23. if(e instanceof Student){
  24. System.out.println("a student");
  25. }
  26. if(e instanceof Person){
  27. System.out.println("a person");
  28. }
  29. //方式二:
  30. if(e instanceof Graduate){
  31. System.out.println("a graduated student");
  32. System.out.println("a student");
  33. System.out.println("a person");
  34. }else if(e instanceof Student){
  35. System.out.println("a student");
  36. System.out.println("a person");
  37. }else{
  38. System.out.println("a person");
  39. }
  40. }
  41. }
  42. class Person {
  43. protected String name = "person";
  44. protected int age = 50;
  45. public String getInfo() {
  46. return "Name: " + name + "\n" + "age: " + age;
  47. }
  48. }
  49. class Student extends Person {
  50. protected String school = "pku";
  51. public String getInfo() {
  52. return "Name: " + name + "\nage: " + age + "\nschool: " + school;
  53. }
  54. }
  55. class Graduate extends Student {
  56. public String major = "IT";
  57. public String getInfo() {
  58. return "Name: " + name + "\nage: " + age + "\nschool: " + school + "\nmajor:" + major;
  59. }
  60. }

练习三
GeometricObject类

  1. /*
  2. * 定义三个类,父类GeometricObject代表几何形状,子类Circle代表圆形,MyRectangle代表矩形。
  3. */
  4. public class GeometricObject {
  5. protected String color;
  6. protected double weight;
  7. public String getColor() {
  8. return color;
  9. }
  10. public void setColor(String color) {
  11. this.color = color;
  12. }
  13. public double getWeight() {
  14. return weight;
  15. }
  16. public void setWeight(double weight) {
  17. this.weight = weight;
  18. }
  19. public GeometricObject(String color, double weight) {
  20. super();
  21. this.color = color;
  22. this.weight = weight;
  23. }
  24. public double findArea(){
  25. return 0.0;
  26. }
  27. }

Circle类

  1. public class Circle extends GeometricObject {
  2. private double radius;
  3. public Circle(double weight,String color, double radius) {
  4. super(color,weight);
  5. this.radius = radius;
  6. }
  7. public double getRadius() {
  8. return radius;
  9. }
  10. public void setRadius(double radius) {
  11. this.radius = radius;
  12. }
  13. @Override
  14. public double findArea() {
  15. return 3.14 * radius * radius;
  16. }
  17. }

MyRectangle类

  1. public class MyRectangle extends GeometricObject {
  2. private double width;
  3. private double height;
  4. public MyRectangle(double width, double height,String color,double weight) {
  5. super(color, weight);
  6. this.height = height;
  7. this.width = width;
  8. }
  9. public double getWidth() {
  10. return width;
  11. }
  12. public void setWidth(double width) {
  13. this.width = width;
  14. }
  15. public double getHeight() {
  16. return height;
  17. }
  18. public void setHeight(double height) {
  19. this.height = height;
  20. }
  21. @Override
  22. public double findArea() {
  23. return width * height;
  24. }
  25. }

GeometricTest类

  1. /*
  2. * 定义一个测试类GeometricTest,编写equalsArea方法测试两个对象的面积是否相等(注意方法的参数类型,利用动态绑定技术),
  3. * 编写displayGeometricObject方法显示对象的面积(注意方法的参数类型,利用动态绑定技术)。
  4. *
  5. */
  6. public class GeometricTest {
  7. public static void main(String[] args) {
  8. GeometricTest test = new GeometricTest();
  9. Circle c1 = new Circle(2.3,"white",1.0);
  10. test.displayGeometricObject(c1);
  11. Circle c2 = new Circle(3.3,"white",1.0);
  12. test.displayGeometricObject(c2);
  13. boolean isEqual = test.equalsArea(c1, c2);
  14. System.out.println("面积是否相等: " + isEqual);
  15. MyRectangle rect = new MyRectangle(2.1, 3.4,"red",1.0);
  16. test.displayGeometricObject(rect);
  17. }
  18. public void displayGeometricObject(GeometricObject o){
  19. System.out.println("面积为: " + o.findArea());
  20. }
  21. //测试两个对象的面积是否相等
  22. public boolean equalsArea(GeometricObject o1,GeometricObject o2){
  23. return o1.findArea() == o2.findArea();
  24. }
  25. }

五、Object类的使用

1.Object类的进阶

  1. /*
  2. * java.lang.Object类
  3. * 1.Object类是所有Java类的根父类;
  4. * 2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
  5. * 3.Object类中的功能(属性、方法)就具有通用性。
  6. * 属性:无
  7. * 方法:equals() / toString() / getClass() / hashCode() / clone() / finalize()
  8. * wait() 、notify()、notifyAll()
  9. * 方法具体用法,后面再说
  10. * 4.Object类只声明了一个空参的构造器。
  11. *
  12. */
  13. public class ObjectTest {
  14. public static void main(String[] args) {
  15. }
  16. }

2.Object类中的主要结构

image.png
下面主要讨论
equals()方法
toString()方法

3.==操作符和equals方法

  1. /**
  2. * 小试牛刀:== 和 equals() 区别
  3. * 一、回顾 == 的使用:
  4. * 1.可以使用在 基本数据类型变量 和 引用数据类型变量 中
  5. * 2.(1).如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。*** 不一定类型要相同 ***
  6. * (2).如果比较的是引用数据类型变量:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体
  7. * 补充:==符号使用时保证两遍变量类型相同***
  8. * 二、equals()方法的使用:
  9. * 1.是一个 方法 而非 运算符
  10. * 2.只适用于 引用数据类型
  11. * 3.Object类中equals()的定义:
  12. * public boolean equals(Object obj){
  13. * return (this == obj);
  14. * }
  15. * 说明:比较的是地址值
  16. * 4.像String、Date、File、包装类等都重写了Object类中的equals()方法.
  17. * 两个引用的地址是否相同,而是比较两个对象的“实体内容”是否相同。
  18. * 5.通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们就需要对Object类中的equals()进行重写。
  19. * 重写的原则:比较两个对象的实体内容是否相同。
  20. * 可以自动生成,没必要自己写哈
  21. */
  22. public class EqualsTest {
  23. public static void main(String[] args) {
  24. //以下是 == 运算符
  25. int j = 10;
  26. int k = 10;
  27. System.out.println(j == k);//true
  28. //类型不同时
  29. double d = 10.0;
  30. System.out.println(j == d);//true。此时,int型自动类型提升为double型也即从10变成了10.0
  31. int m = 65;
  32. char n = 'A';
  33. System.out.println(m == n);//true。ASCII表: A --> 65, a --> 97
  34. //比较对象为引用数据类型变量
  35. Person p1 = new Person("Jiaran", 21);
  36. Person p2 = new Person("Jiaran", 21);
  37. System.out.println(p1 == p2);//false。比较的是引用数据类型变量,比较的是地址值,很明显不相同
  38. //以下是equals()方法
  39. System.out.println(p1.equals(p2));//false。equals比较的也是地址值,故返回false
  40. //那么当引用数据类型变量是String呢?
  41. String str1 = new String("关注嘉然,顿顿解馋");
  42. String str2 = new String("关注嘉然,顿顿解馋");
  43. System.out.println(str1.equals(str2));//true!因为String类中重写了equals()方法比较的是实体内容
  44. System.out.println(str1 == str2);//false!因为这个可没有什么重写,单纯的比较地址值
  45. }
  46. }
  47. class Person{
  48. String name;
  49. int age;
  50. Person(String name,int age){
  51. this.name = name;
  52. this.age = age;
  53. }
  54. //尝试手动重写一个比较name和age的equals()方法
  55. public boolean equals(Object obj){
  56. //判断两个引用是否相同
  57. if(this == obj){
  58. return true;
  59. }
  60. if(obj instanceof Person){//判断传入对象是不是Person类中的
  61. Person p = (Person)obj;
  62. if(this.age == p.age && this.name.equals(p.name)){
  63. return true;
  64. }else{
  65. return false;
  66. }
  67. }
  68. return false;
  69. }
  70. }

4.== 和 equals 总结

对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。
>自反性:x.equals(x)必须返回是“true”。
>传递性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是 “true”。
>一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是 “true”。
>任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。

  1. int it = 65;
  2. float fl= 65.0f;
  3. System.out.println("65和65.0f是否相等?" + (it == fl)); //true
  4. char ch1 = 'A';
  5. char ch2 = 12;
  6. System.out.println("65和'A'是否相等?" + (it == ch1));//true
  7. System.out.println("12和ch2是否相等?" + (12 == ch2));//true
  8. String str1 = new String("hello");
  9. String str2 = new String("hello");
  10. System.out.println("str1和str2是否相等?"+ (str1 == str2));//false
  11. System.out.println("str1是否equals str2?"+(str1.equals(str2)));//true
  12. System.out.println("hello" == new java.util.Date()); //编译不通过,补充:==符号使用时保证两遍变量类型相同

5.equals方法的练习

练习一 ```java /*

  • 编写Order类,有int型的orderId,String型的orderName,
  • 相应的getter()和setter()方法,两个参数的构造器,重写父类的equals()方法:public boolean equals(Object obj){}
  • 并判断测试类中创建的两个对象是否相等。 */ public class OrderTest { public static void main(String[] args) {
    1. Order order1 = new Order(1001,"AA");
    2. Order order2 = new Order(1001,"BB");
  1. System.out.println(order1.equals(order2)); //false
  2. Order order3 = new Order(1001,"BB");
  3. System.out.println(order2.equals(order3)); //true
  4. }

}

class Order{ private int orderId; private String orderName; public int getOrderId() { return orderId; } public void setOrderId(int orderId) { this.orderId = orderId; } public String getOrderName() { return orderName; } public void setOrderName(String orderName) { this.orderName = orderName; } public Order(int orderId, String orderName) { super(); this.orderId = orderId; this.orderName = orderName; } //尝试重写equals方法 public boolean equals(Object obj){ //判断是否是一个对象 if(this == obj){
return true; } //判断是不是子类(该类)的一个实例 if(obj instanceof Order){ Order order = (Order)obj; //正确的 return this.orderId == order.orderId && this.orderName.equals(order.orderName); //错误的,因为orderName为String //return this.orderId == order.orderId && this.orderName == order.orderName; } return false; } }

  1. **练习二**
  2. ```java
  3. /*
  4. * 请根据以下代码自行定义能满足需要的MyDate类,在MyDate类中覆盖equals方法,
  5. * 使其判断当两个MyDate类型对象的年月日都相同时,结果为true,否则为false。
  6. * public boolean equals(Object o)
  7. */
  8. public class MyDateTest {
  9. public static void main(String[] args) {
  10. MyDate m1= new MyDate(14, 3, 1976);
  11. MyDate m2= new MyDate(14, 3, 1976);
  12. if(m1== m2) {
  13. System.out.println("m1==m2");
  14. } else{
  15. System.out.println("m1!=m2"); // m1 != m2
  16. }
  17. if(m1.equals(m2)) {
  18. System.out.println("m1 is equal to m2");// m1 is equal to m2
  19. } else{
  20. System.out.println("m1 is not equal to m2");
  21. }
  22. }
  23. }
  24. class MyDate {
  25. private int year;
  26. private int month;
  27. private int day;
  28. public MyDate(int year,int month,int day){
  29. this.year = year;
  30. this.month =month;
  31. this.day =day;
  32. }
  33. public int getDay() {
  34. return day;
  35. }
  36. public void setDay(int day) {
  37. this.day = day;
  38. }
  39. public int getMonth() {
  40. return month;
  41. }
  42. public void setMonth(int month) {
  43. this.month = month;
  44. }
  45. public int getYear() {
  46. return year;
  47. }
  48. public void setYear(int year) {
  49. this.year = year;
  50. }
  51. @Override
  52. public boolean equals(Object obj) {
  53. if(this == obj){
  54. return true;
  55. }
  56. if(obj instanceof MyDate){
  57. MyDate myDate = (MyDate)obj;
  58. return this.day == myDate.day && this.month == myDate.month && this.year == myDate.year;
  59. }
  60. return false;
  61. }
  62. //自动生成的
  63. // @Override
  64. // public boolean equals(Object obj) {
  65. // if (this == obj)
  66. // return true;
  67. // if (obj == null)
  68. // return false;
  69. // if (getClass() != obj.getClass())
  70. // return false;
  71. // MyDate other = (MyDate) obj;
  72. // if (day != other.day)
  73. // return false;
  74. // if (month != other.month)
  75. // return false;
  76. // if (year != other.year)
  77. // return false;
  78. // return true;
  79. // }
  80. }

6.toString()的使用

  1. import java.util.Date;
  2. /**
  3. * Object类中toString()方法使用:
  4. * 1.当我们输出一个对象的引用时就是默认调用当前对象的toString()方法
  5. * 2.Object类中toString()方法的定义:
  6. * public String toString() {
  7. * return getClass().getName() + "@" + Integer.toHexString(hashCode());
  8. * }
  9. * 3.像String、Date、File、包装类等都重写了Object类中的toString()方法。
  10. * 使得在调用toString()时,返回"***实体内容***"信息.
  11. * 4.自定义类如果重写toString()方法,当调用此方法时,返回对象的"实体内容".
  12. */
  13. public class ToStringTest {
  14. public static void main(String[] args) {
  15. //普通
  16. Customer c1 = new Customer("Tom", 21);
  17. System.out.println(c1.toString());//打印类名+地址
  18. System.out.println(c1);//两者输出相同,即只单独打印对象的引用时,默认调用toString()方法
  19. //对 String 和 Date
  20. String str = new String("嘉然");
  21. System.out.println(str);//这里不输出地址,而输出嘉然!因为String重写了toString()方法
  22. Date date = new java.util.Date(45645646564654L);
  23. System.out.println(date);//不输出地址,而输出具体日期!Date也重写了!
  24. }
  25. }
  26. class Customer{
  27. String name;
  28. int age;
  29. public Customer(String name,int age){
  30. this.name = name;
  31. this.age = age;
  32. }
  33. //手动重写toString()方法
  34. @Override
  35. public String toString() {
  36. return "这个人的名字为" + this.name + "年龄为" + this.age;
  37. }
  38. }

7.Object类综合练习

GeometricObject类

  1. public class GeometricObject {
  2. protected String color;
  3. protected double weight;
  4. public GeometricObject() {
  5. super();
  6. this.color = "white";
  7. this.weight = 1.0;
  8. }
  9. public GeometricObject(String color, double weight) {
  10. super();
  11. this.color = color;
  12. this.weight = weight;
  13. }
  14. public String getColor() {
  15. return color;
  16. }
  17. public void setColor(String color) {
  18. this.color = color;
  19. }
  20. public double getWeight() {
  21. return weight;
  22. }
  23. public void setWeight(double weight) {
  24. this.weight = weight;
  25. }
  26. }

Circle类

  1. public class Circle extends GeometricObject{
  2. private double radius;
  3. public Circle() { //初始化对象的color属性为“white”,weight属性为1.0,radius属性为1.0。
  4. super(); //super自带,不需再写
  5. // this.color = "white";
  6. // this.weight = 1.0;
  7. this.radius = 1.0;
  8. }
  9. //初始化对象的color属性为“white”,weight属性为1.0,radius根据参数构造器确定。
  10. public Circle(double radius) {
  11. super(); //super自带,不需再写
  12. // this.color = "white";
  13. // this.weight = 1.0;
  14. this.radius = radius;
  15. }
  16. public Circle(double radius,String color,double weight) {
  17. super(color,weight);
  18. this.radius = radius;
  19. }
  20. public double getRadius() {
  21. return radius;
  22. }
  23. public void setRadius(double radius) {
  24. this.radius = radius;
  25. }
  26. //计算圆的面积
  27. public double findArea(){
  28. return Math.PI * radius * radius;
  29. }
  30. @Override //重写equals方法,比较两个圆的半径是否相等,如相等,返回true。
  31. public boolean equals(Object obj) {
  32. if(this == obj){
  33. return true;
  34. }
  35. //判断是不是Circle的实例
  36. if(obj instanceof Circle){
  37. Circle c = (Circle)obj;
  38. return this.radius == c.radius;
  39. }
  40. return false;
  41. }
  42. @Override
  43. public String toString() { //重写toString方法,输出圆的半径。
  44. return "Circle [radius=" + radius + "]";
  45. }
  46. }

测试类

  1. /*
  2. * 写一个测试类,创建两个Circle对象,判断其颜色是否相等;
  3. * 利用equals方法判断其半径是否相等;利用toString()方法输出其半径。
  4. *
  5. */
  6. public class CircleTest {
  7. public static void main(String[] args) {
  8. Circle circle1 = new Circle(2.3);
  9. Circle circle2 = new Circle(3.3,"white",2.0);
  10. //这里调用的equals方法,非前面Circle类中重写的,而是String中的重写equals!
  11. System.out.println("颜色是否相等: " + circle1.getColor().equals(circle2.color));
  12. System.out.println("半径是否相等: " + circle1.equals(circle2));
  13. System.out.println(circle1);
  14. System.out.println(circle2.toString());
  15. }
  16. }

六、包装类(Wrapper)的使用

1.单元测试方法的使用

  1. import java.util.Date;
  2. import org.junit.Test;
  3. /*
  4. * java中的JUnit单元测试
  5. *
  6. * 步骤:
  7. * 1.选中当前项目工程 --》 右键:build path --》 add libraries --》 JUnit 4 --》 下一步
  8. * 2.创建一个Java类进行单元测试。
  9. * 此时的Java类要求:①此类是公共的 ②此类提供一个公共的无参构造器
  10. * 3.此类中声明单元测试方法。
  11. * 此时的单元测试方法:方法的权限是public,没有返回值,没有形参。
  12. *
  13. * 4.此单元测试方法上需要声明注解:@Test并在单元测试类中调用:import org.junit.Test;
  14. * 5.声明好单元测试方法以后,就可以在方法体内测试代码。
  15. * 6.写好代码后,左键双击单元测试方法名:右键 --》 run as --》 JUnit Test
  16. *
  17. * 说明:如果执行结果无错误,则显示是一个绿色进度条,反之,错误即为红色进度条。
  18. */
  19. public class JUnit {
  20. int num = 10;
  21. //第一个单元测试方法
  22. @Test
  23. public void testEquals(){
  24. String s1 = "MM";
  25. String s2 = "MM";
  26. System.out.println(s1.equals(s2));
  27. //ClassCastException的异常
  28. // Object obj = new String("GG");
  29. // Date date = (Date)obj;
  30. System.out.println(num);
  31. show();
  32. }
  33. public void show(){
  34. num = 20;
  35. System.out.println("show()...");
  36. }
  37. //第二个单元测试方法
  38. @Test
  39. public void testToString(){
  40. String s2 = "MM";
  41. System.out.println(s2.toString());
  42. }
  43. }

2.包装类的使用

  1. /*
  2. * 包装类的使用
  3. * 1.java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征
  4. * 基本数据类型 包装类
  5. * byte Byte
  6. * short Short
  7. * int Integer
  8. * long Long
  9. * float Float
  10. * double Double
  11. * boolean Boolean
  12. * char Character
  13. * 注意:其中Byte、Short、Integer、Long、Float、Double的父类是:Number
  14. * /

3.包装类与基本数据类型相互转换

  1. /**
  2. * 包装类的使用:
  3. * 1.Java中提供了八种数据类型的包装类,使基本数据类型具有类的特征
  4. * 2.掌握 基本数据类型 包装类 String 三者之间的转换
  5. */
  6. public class WrapperTest{
  7. public static void main(String[] args) {
  8. //基本数据类型 --> 包装类
  9. //Integer
  10. int num1 = 10;
  11. Integer n1 = new Integer(num1);
  12. System.out.println(n1.toString());
  13. //构造器中为String是必须要为一个数,否则会报错
  14. Integer n2 = new Integer("123");
  15. System.out.println(n2.toString());
  16. //Float
  17. Float f1 = new Float(12.3f);
  18. System.out.println(f1);
  19. Float f2 = new Float("12.3");
  20. System.out.println(f2);
  21. //Boolean
  22. Boolean b1 = new Boolean(true);
  23. Boolean b2 = new Boolean("true");
  24. Boolean b3 = new Boolean("true123");//false
  25. //特殊的包装类
  26. order o = new order();
  27. System.out.println(o.isMale);//false;基本数据类型,默认值false
  28. System.out.println(o.isFemale);//null;这时是类了地位高了,默认值变成null了
  29. //包装类 --> 基本数据类型
  30. Integer in1 = new Integer(12);
  31. int num1 = in1.intValue();
  32. System.out.println(num1 + 1);//13
  33. Float f1 = new Float(12.3);
  34. float f2 = f1.floatValue();
  35. System.out.println(f2 + 1)//12.3
  36. }
  37. }
  38. class order{
  39. boolean isMale;
  40. Boolean isFemale;
  41. }

image.png

4.JDK5.0新特性:自动装箱与拆箱

  1. public class WrapperTest{
  2. public static void main(String[] args) {
  3. //自动装箱
  4. int i1 = 233;
  5. Integer in1 = i1;
  6. System.out.println(in1.toString());//233
  7. //自动拆箱
  8. Integer in2 = new Integer(12);
  9. int i2 = in2;
  10. System.out.println(i2);//12
  11. }
  12. }

5.String和基本数据类型、包装类相互转换

  1. /**
  2. * 包装类的使用:
  3. * 1.Java中提供了八种数据类型的包装类,使基本数据类型具有类的特征
  4. * 2.掌握 基本数据类型 包装类 String 三者之间的转换
  5. */
  6. public class WrapperTest{
  7. public static void main(String[] args) {
  8. //基本数据类型、包装类 --> String
  9. int num = 10;
  10. //方式一:连接运算
  11. String str1 = num + "";
  12. //方式二:调用String重载的valueOf(Xxx xxx)某一个类型的某一个变量
  13. String str2 = String.valueOf(num);//基本数据类型可以做参数
  14. Integer in = 10;
  15. String str3 = String.valueOf(in);//包装类也行
  16. //基本数据类型、String --> 基本数据类型、包装类
  17. String str4 = "123";
  18. String str5 = "true";
  19. //调用包装类中parseInt()
  20. int num2 = Integer.parseInt(str4);
  21. System.out.println(num2 + 1);//124
  22. Boolean b1 = Boolean.parseBoolean(str5);
  23. System.out.println(b1); //true
  24. }
  25. }

6.练习

  1. public class InterViewTest {
  2. //细细品味
  3. @Test
  4. public void test(){
  5. Object o1= true? new Integer(1) : new Double(2.0);
  6. System.out.println(o1);// 1.0
  7. }
  8. @Test
  9. public void test2(){
  10. Object o2;
  11. if(true)
  12. o2 = new Integer(1);
  13. else
  14. o2 = new Double(2.0);
  15. System.out.println(o2);// 1