首页 > 其他分享 >面向对象(进阶篇)

面向对象(进阶篇)

时间:2023-10-20 12:44:58浏览次数:30  
标签:面向对象 子类 System 进阶篇 println 父类 public out

面向对象(进阶篇)

1. this关键字的使用(当前对象)

  1. 遇到的问题,以及对应的解决方案

    • 在声明属性的setXxx方法时,如果形参和对应的属性重名,如何在方法中区分两者

    • 使用this关键字可以解决上述问题。

    • 具体来说:使用this修饰的是属性,不使用this修饰的是局部变量

  2. this可以调用的结构:成员变量,方法,构造器

  3. this的理解:this代表的是当前的对象(在方法的调用时),代表正在创建的对象(在构造器调用时)

  4. this调用属性和方法

    【针对于方法内的】

    • 一般情况:我们通过对象a调用方法,可在方法内调用当前对象a的属性和其他方法,此时我们可以用this.来表示当前属性或方法属于对象a,但是一般情况下都省略this.
    • 特殊情况:如果方法名中的形参列表和属性的名字一样,可以使用this.的方式来区分谁是成员变量,谁是局部变量

    【针对于构造器的】

    • 一般情况:我们通过构造器创建对象,可在构造器调用当前对象的属性和方法,此时我们可以用this.来表示当前属性或方法属于该对象,但是一般情况下都省略this.
    • 特殊情况:如果构造其中的形参列表和对象的属性的名字一样,可以使用this.的方式来区分谁是成员变量,谁是局部变量
  5. this调用构造器

    • 使用构造器调用对象:格式:this(形参列表)this()调用空参

    • 在类的构造器中调用其他构造器(不能自己调用自己,形成递归无法退出)

    • 要求构造器调用只能写在首行

    • 一个构造器只能存在一个构造器的调用

1.1 练习

  • 男孩女孩this练习
    public void marry(Girl girl) {
        System.out.println(girl.getName() + "愿意和我结婚吗?");
        girl.marry(this);
    }

    public void shout() {
        if (age > 22) {
            System.out.println("我终于可以结婚了");
        } else {
            System.out.println("我只能和你谈恋爱");
        }
    }
    public void marry(Boy boy) {
        System.out.println(boy.getName() + "我愿意");

    }

    public int compare(Girl girl) {
        if (this.age > girl.age) {
            return 1;
        } else if (this.age < girl.age) {
            return -1;
        } else {
            return 0;
        }
    }
package com.ygc.oop03._thisExer;

/**
 * @author: YGC
 * @createTime: 2023/09/04 8:58
 * @blogs: <a href="https://www.cnblogs.com/ygcDiary"></a>
 * @description: 测试
 */
public class BoyGirlTest {
    public static void main(String[] args) {
        Boy boy = new Boy("姚贵春", 24);
        Girl girl = new Girl("杨泽荣", 17);
        boy.marry(girl);
        Girl girl1 = new Girl("rose", 18);
        girl.compare(girl);
        if (girl.getAge() > girl1.getAge()) {
            System.out.println(girl.getName() + "大");
        } else if (girl.getAge() < girl1.getAge()) {
            System.out.println(girl1.getName() + "大");
        } else {
            System.out.println("一样大");
        }
    }
}

  • 账户练习
package com.ygc.oop03._thisExer01;

/**
 * @author: YGC
 * @createTime: 2023/09/04 9:12
 * @blogs: <a href="https://www.cnblogs.com/ygcDiary"></a>
 * @description: 银行账户
 */
public class Account {
    private double balance;

    public Account(double init_balance) {
        this.balance = init_balance;
    }

    public double getBalance() {
        return balance;
    }

    public void deposit(double amt) {
        balance += amt;
        System.out.println("存款成功:" + amt + "元");
    }

    public void withdraw(double amt) {
        if (amt > balance) {
            System.out.println("您的余额不足!");
        } else {
            balance -= amt;
            System.out.println("取款成功");
        }
    }
}

package com.ygc.oop03._thisExer01;

/**
 * @author: YGC
 * @createTime: 2023/09/04 9:22
 * @blogs: <a href="https://www.cnblogs.com/ygcDiary"></a>
 * @description: 银行
 */
public class Bank {
    private Customer[] customers;
    private int numberOfCustomer;

    public Bank() {
        customers = new Customer[10];
    }

    public void addCustomer(String f, String l) {
        Customer customer = new Customer(f, l);
        customers[numberOfCustomer] = customer;
        numberOfCustomer++;
        System.out.println("增加账户成功:" + f + l);
    }

    public int getNumOfCustomer() {
        return numberOfCustomer;
    }

    public Customer getCustomer(int index) {
        if (index < 0 || index > numberOfCustomer) {
            return null;
        } else {
            return customers[index];
        }
    }
}

package com.ygc.oop03._thisExer01;

/**
 * @author: YGC
 * @createTime: 2023/09/04 9:18
 * @blogs: <a href="https://www.cnblogs.com/ygcDiary"></a>
 * @description: 客户
 */
public class Customer {
    private String firstName;
    private String lastName;
    private Account account;

    public Customer(String f, String l) {
        this.firstName = f;
        this.lastName = l;
    }

    public String getFirstName() {
        return firstName;
    }


    public String getLastName() {
        return lastName;
    }

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }
}

package com.ygc.oop03._thisExer01;

/**
 * @author: YGC
 * @createTime: 2023/09/04 9:38
 * @blogs: <a href="https://www.cnblogs.com/ygcDiary"></a>
 * @description: 测试
 */
public class BankTest {
    public static void main(String[] args) {
        Bank bank = new Bank();
        bank.addCustomer("jack", "11");
        //取钱,通过匿名对象,创建账户,并通过构造器,赋值balance为1000
        bank.getCustomer(0).setAccount(new Account(1000));
        bank.getCustomer(0).getAccount().withdraw(100);
        System.out.println("账户余额为:" + bank.getCustomer(0).getAccount().getBalance());
        //通过账户来进行取钱方法
        bank.addCustomer("rose", "22");
        bank.getCustomer(1).setAccount(new Account(10000));
        bank.getCustomer(1).getAccount().withdraw(100);
        System.out.println(bank.getCustomer(1).getAccount().getBalance());
    }
}
  • 内存解析:

image-20230907212818675

2. 继承性

2.1 问题的引入

  1. 在定义类A,在定义了类B时,发现类B和类A的功能相似,考虑使用继承,B继承A的功能

  2. 定义了类B,C,D等,B,C,D有相同的属性和方法,则考虑将相同的方法抽取,封装到类A中,让B,C,D继承

    同时B,C,D中的对应的属性和方法就可以删除了

2.2 继承性的好处

  1. 减少了代码的冗余
  2. 继承的出现,更有利于功能的扩展,提高代码的复用性
  3. 继承描述了事物之间的所属关系,is-a,由此可见,父类更通用,子类更具体
  4. 实际上,封装性并不受继承的影响,继承了私有属性,仍然不能访问
  • 代码实例
public class Extend_Exer {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "jack";
        person.age = 20;

        Student student = new Student();
        System.out.println(student.name = "ygc");
        System.out.println(student.age = 12);
    }
}

public class Person {
    String name;
    int age;

    public void eat() {
        System.out.println("吃饭");
    }
}
public class Student extends Person {
    //    private String name;
//    private int age;
    private int grade;

//    public void eat() {
//        System.out.println("吃饭");
//    }
}

2.3 默认的父类

java,没有显示的的声明其父类时,默认继承java.lang.object

//获取student的父类
        System.out.println(student.getClass().getSuperclass());//class com.ygc.extend01.Person
        //获取person的父类
        System.out.println(person.getClass().getSuperclass());//class java.lang.Object

2.4 补充说明

  1. 支持多级层继承(直/间接父类)
  2. java子父类是相对的
  3. java的一个父类可以声明多个子类,但是一个子类只能继承一个父类

2.5 权限修饰符的访问范围

修饰符 本类内部 本包内 其他包的子类 其他包非子类
private × × ×
缺省 × ×
protected ×
public

3.方法的重写(overwrite / override)

  • 为什么需要重写:

子类在继承了父类之后,获得了父类的所有属性和方法,但是父类的方法可能存在功能不完善的缺点,子类继承的时候,需要对父类该方法进行覆写、覆盖

  1. 何为重写:

    • 方法的重写的定义:子类对父类继承的方法的覆盖
  2. 重新应该遵循的规则:

    • 方法的声明格式:权限修饰符 返回值类型 方法名(形参列表){}
    • 重写的规则依据方法的定义的规则:
      • 父类被重写的方法应该与子类重写的方法名和形参列表保持一致
      • 子类重写的方法的权限修饰,不小于父类的权限修饰符
        • 子类不能重写父类中的private方法
      • 返回值类型:
        1. 无返回值类型时:父类无返回值,子类应该也无返回值
        2. 有返回值时:
          1. 返回值是基本数据类型时:子类与父类的返回值类型相同
          2. 返回值是引用数据类型时:子类的返回值可以是父类的返回值,或者父类的其他子类本身
      • 重写的方法抛出的异常都类型相同,或者是父类的子类。
    1. 重载和重写的区别:
      • 重载:”两同一不同“:类相同,方法名相同,参数列表不同
      • 重写:发生在继承之后,子类覆盖父类的方法

4. Super

  • 为什么需要super呢?
  1. 在子类继承父类之后,父类中的方法如果发生重写,在子类其他的方法中,无法在调用父类已经写好的方法,这显然是不符合逻辑的,这时候,super就能解决这样的问题。

  2. 子类在继承父类之后发现子类和父类中定义了同名的属性,可以通过super来区分这两个变量

  3. 如何调用:

    • 使用super关键字即可
      • 调用属性、方法:
        • 子类在继承父类之后,使用super关键字,直接调用父类中的属性或者方法,如果不添加super关键字,则默认先找子类,没有此方法或者属性时才会去父类找这个方法或属性子类构造器默认有一个super()
        • 一般情况下可以省略,如果子类重写了父类的方法或子类和父类出现了同名的属性时,必须通过super的方法调用父类的方法,或者同名的属性
      • 调用构造器
        • super和this一样的要求
        • super和this调用构造器,只能出现一个(他俩都必须在首行)
        • 如果子类没有写调用构造器,子类会默认调用一个空参的父类的构造器
       Student_Super studentSuper1 = new Student_Super(213, "sadad");
    //00000000000000
    
        public Student_Super(int id, String school) {
        }
    
        public Person() {
            System.out.println("00000000000000");
        }
    
  • 在定义子类的对象时,同时初始化父类的属性(调用父类的构造器)
 //通过super的方式,将父类拿到的值,在子类中进行初始化,达到共享值的目的
		Student_Super studentSuper1 = new Student_Super("ygc", 18);
        System.out.println(studentSuper1.getAge());
        System.out.println(studentSuper1.getName());
 public Student_Super(String name, int age) {
        super(name, age);
    }
  public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
  1. super的含义:父类的

实例:透支(super)

package super_Exer;

public class CheckAccountTest {
    public static void main(String[] args) {
        CheckAccount checkAccount = new CheckAccount(1, 500, 0.045, 600);
        checkAccount.withdraw(700);
    }
}

  • CheckAccount(继承父类account)
package super_Exer;

public class CheckAccount extends Account {
    private double overdraft;

    public CheckAccount(int id, double balance, double annualInterestRate) {
        super(id, balance, annualInterestRate);
    }

    public CheckAccount(int id, double balance, double annualInterestRate, double overdraft) {
        super(id, balance, annualInterestRate);
        this.overdraft = overdraft;
    }

    public void withdraw(double amount) {
        if (amount < getBalance()) {
            System.out.println("您可以直接取款!");
            super.withdraw(amount);
        } else {
            if (overdraft + getBalance() < amount) {
                System.out.println("您的可用额度不足");
            } else {
                //取出所有的的钱
                overdraft -= amount - getBalance();
                super.withdraw(getBalance());
                System.out.println("取款成功!您的剩余额度是" + overdraft);
            }
        }
    }
}

  • Account
package super_Exer;

public class Account {
    private int id;
    private double balance;
    private double annualInterestRate;


    public Account(int id, double balance, double annualInterestRate) {
        this.id = id;
        this.balance = balance;
        this.annualInterestRate = annualInterestRate;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public double getBalance() {
        return balance;
    }
    

    public double getAnnualInterestRate() {
        return annualInterestRate;
    }

    public void setAnnualInterestRate(double annualInterestRate) {
        this.annualInterestRate = annualInterestRate;
    }

    public double getMonthlyInterest() {
        return annualInterestRate / 12;
    }

    public void withdraw(double amount) {
        if (balance < amount) {
            System.out.println("余额不足!");
            System.out.println("余额为:" + balance);
        } else {
            balance -= amount;
            System.out.println("取款成功!余额为:" + balance);
            System.out.println("您的月利率是:" + getMonthlyInterest());
        }
    }

    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        } else {
            System.out.println("你输入的有误");
        }
    }

}

  • AccountTest
package super_Exer;

public class AccountTest {
    public static void main(String[] args) {
        Account account = new Account(1, 30000.0, 0.45);
        account.withdraw(40000);
    }
}

5. 多态性

  1. Java中多态的体现:

    • 父类的引用指向子类的对象:
    • 声明一个父类的对象,却构造了一个子类的对象。
  2. 多态的应用:

    • 虚拟方法调用: 虚拟方法的调用,编译器认为是父类,实际是调用子类的方法
    Person person = new Man();
    
    person.eat();//调用的是子类的方法
    
  3. 多态的使用前提:

    • 要有继承关系
    • 要有方法的重写
  4. 多态的适用性:

    • 仅适用于方法,不适用属性
  5. 多态的好处:

    • 在开发中使用最多的是:用父类作为方法的形参,即使增加了新的子类,也不需要改变方法,提高了扩展性,符合开闭原则

    【开闭原则】:

    • 对扩展开放,对修改关闭
    • 软件中各种组件如:类,模块,功能等,应该不修改现有代码的基础上增加新的功能
  6. 多态的弊端:

    • 在内存中实际是存在子类对象的,但是无法直接调用子类的属性和特殊的方法【父类是一个泛化的概念,无法指定为一个特殊子类,所以不能调用子类特有的属性和方法也是合情合理的】
  7. 虚方法的调用:编译看左边,运行看右边,属性不存在多态

6. 向下转型

【解决多态弊端:】

  1. 向上转型:可以类比为自动类型提升(多态)
  2. 向下转型:可以理解为强制类型转换
    • 指向对空间的同一个对象
  3. 向下转型可能会出现:类型转换的异常 :ClassCastException编译器不会报错
  4. 建议在向下转型的时候加入instanceof关键字判断:提升程序的健壮性
    * 如果判断结果为真,那么其父类,超类都能成立
package duotai_gainian;

/**
 * @author: YGC
 * @createTime: 2023/09/28 14:25
 * @blogs: <a href="https://www.cnblogs.com/ygcDiary"></a>
 * @description:
 */
public class PersonTest01 {
    public static void main(String[] args) {
        Person p1 = new Man();
        //向下转型:指向对空间的同一个对象
        Man man = (Man) p1;
        man.earnMoney();
        /*
         * 向下转型可能会出现:类型转换的异常:ClassCastException
         * 编译器不会报错
         * */
        Person p2 = new Woman();
        //Man w2 = (Man) p2;
        //w2.earnMoney();//
 		System.out.println("=====================");
        /*
         * 建议在向下转型的时候加入instanceof关键字判断
         * 避免出现错误
         * */
        if (p2 instanceof Man) {
            Man w2 = (Man) p2;
            System.out.println("w2对象是一个男人");//不输出
        }
        if (p2 instanceof Woman) {
            System.out.println("w2对象是一个女人");//输出
        }
    }
}
  • 练习:
package duotai_Exer.exer03;

/**
 * @author: YGC
 * @createTime: 2023/09/28 15:31
 * @blogs: <a href="https://www.cnblogs.com/ygcDiary"></a>
 * @description:
 */
public class Per {
    public void method(Person e) {
        System.out.println(e.getInfo());
        if (e instanceof Person) {
            System.out.println("a person");
        }
        if (e instanceof Student) {
            System.out.println("a Student");
            System.out.println("a person");
        }
        if (e instanceof Graduate) {
            System.out.println("a graduated student" + "a student" + "a person");
        }
    }

    public static void main(String[] args) {
        Per per = new Per();
        per.method(new Person());
    }
}

class Person {
    protected String name = "person";
    protected int age = 50;

    public String getInfo() {
        return "Name: " + name + "\n" + "age: " + age;
    }
}

class Student extends Person {
    protected String school = "pku";

    public String getInfo() {
        return "Name: " + name + "\nage: " + age
                + "\nschool: " + school;
    }
}

class Graduate extends Student {
    public String major = "IT";

    public String getInfo() {
        return "Name: " + name + "\nage: " + age
                + "\nschool: " + school + "\nmajor:" + major;
    }
}



  • instanceOf的使用
package duotai_Exer.exer04;

/**
 * @author: YGC
 * @createTime: 2023/09/28 15:49
 * @blogs: <a href="https://www.cnblogs.com/ygcDiary"></a>
 * @description:
 */
public class Exer4 extends Person {
    public static void meeting(Person... ps) {
        for (int i = 0; i < ps.length; i++) {
            ps[i].eat();
            ps[i].toilet();
            if (ps[i] instanceof Man) {
                Man man = (Man) ps[i];
                man.smoke();
            }
            if (ps[i] instanceof Woman) {
                Woman woman = (Woman) ps[i];
                woman.makeup();
            }
            System.out.println("================");
        }


    }

    public static void main(String[] args) {
        Exer4 exer4 = new Exer4();
        meeting(new Man(), new Woman());
    }
}

package duotai_Exer.exer04;

public class Man extends Person {
    public void eat() {
        System.out.println("男人大口吃饭");
    }

    @Override
    public void toilet() {
        System.out.println("男人上厕所");
    }

    public void smoke() {
        System.out.println("男人抽烟");
    }
}

package duotai_Exer.exer04;

public class Person {
    public void eat() {
        System.out.println("人吃饭");
    }

    public void toilet() {
        System.out.println("上洗手间");
    }
}

package duotai_Exer.exer04;

public class Woman extends Person {
    @Override
    public void eat() {
        System.out.println("女人小口吃饭");
    }

    @Override
    public void toilet() {
        System.out.println("女人上厕所");
    }

    public void makeup() {
        System.out.println("女人化妆");
    }
}

【总结:】

  1. 编译属性看左边
  2. 运行方法看右边
  3. 属性不覆盖,多态谈方法

7. Object中常用的方法

  1. clone():克隆一个新的对象实际上是构建了一个新的对象,在堆内存中实际new了一个(不常用)

  2. finalize:在jdk8之后不推荐使用这个方法,这个方法是在垃圾回收器GC执行之前,做一些操作(不常用)

  3. equals():

    • 适用性:

      • 任何引用数据类型都可以使用
       		User u1 = new User();
              u1.setName("ygc");
              u1.setAge(18);
              User u2 = new User();
              u2.setName("yzr");
              u2.setAge(18);
              System.out.println(u1.equals(u2));//false
      
      • 说明:比较两个一一引用数据类型是否相等,调用的是object中的equals()方法
      • equals和==的区别:
        • ==:就是一个运算符
          • 基本数据类,引用数据类型都可以使用
          • 对于基本数据类型:==比较数值
          • 对于引用数据类型:==比较地址值
        • equals():
          • 是一个方法
          • 只可以对引用数据类型
       		String str1 = new String("hello");
              String str2 = new String("hello");
              System.out.println(str1 == str2);//false
              System.out.println(str1.equals(str2));//true
      
      • 对于String、File、Date和各种包装类,他们都重写了equals方法,用于比较两个对象实体是否相等
      //重写equals方法,比较两个对象实体的属性是否相同
          @Override
          public boolean equals(Object obj) {
              if (this == obj) {
                  return true;
              }
              if (obj instanceof User) {
                  User user = (User) obj;
                  return this.age == user.age && this.name.equals(name);
              }
              return false;
          }
      
      • IDEA自动实现(alt+insert+equals)
       @Override
          public boolean equals(Object o) {
              if (this == o) return true;
              if (o == null || getClass() != o.getClass()) return false;
              User user = (User) o;
              return age == user.age && Objects.equals(name, user.name);
          }
      
      • 在实际开发中,Object提供的equals方法并不能满足需求,需要使用重写,判断属性是否相同
  4. toSting :(自述方法,重写后跟返回对象的是实体内容)

    • 默认的使用Object中定义的方法,但是实际开发中是需要重写的
    • 子类的声明:
      • 对于String、File、Date和各种包装类,已经重写了调用时,返回当前实体的内容

标签:面向对象,子类,System,进阶篇,println,父类,public,out
From: https://www.cnblogs.com/ygcDiary/p/17776807.html

相关文章

  • 面向对象(高级篇)
    面向对象(高级篇)1.关键字:static静态变量,所有的类可以共享该变量static:静态的用来修饰结构:属性、方法、代码块、内部类static修饰属性:成员变量:按照是否使用static修饰:使用static修饰的:静态变量、类变量(属性)jdk6及以前存放在方法区、jdk7以后存放在堆内存所有对......
  • 【Java 进阶篇】使用 JDBC 更新数据详解
    在关系型数据库中,更新数据是一项常见的任务。通过JavaJDBC(JavaDatabaseConnectivity),我们可以使用Java编程语言来执行更新操作,例如修改、删除或插入数据。本文将详细介绍如何使用JDBC来进行数据更新操作,包括示例代码和必要的概念。JDBC更新操作概述在JDBC中,更新操作通常分为以下......
  • Java拾贝第三天——面向对象2
    继承性面向对象三大特性:封装性,继承性,多态性。继承的作用是避免出现大幅度的相同代码,提高代码的复用性。//现有一个Person类,拥有name,age属性classPerson{privateStringname;privateintage;//构造方法和setter,getter现在有一个Student类,它和Person类的属性......
  • day02-面向对象
    面向过程&面向对象面向过程--线性步骤清晰简单,第一步做什么,第二步做什么面向过程适合处理一些较为简单的问题面向对象物以类聚,分类的思维模式,思考问题首先会解决问题需要那些分类,然后对这些分类进行单独思考。最好,才对某个分类下的细节进行面向过程的思索。面向对象适合处......
  • Java拾贝第二天——面向对象
    Java拾贝不建议作为0基础学习,都是本人想到什么写什么特性封装性,继承性,多态性。类的组成publicclass类名{//数据类型属性名;intage;//成员变量public返回值类型方法名(传参){ Stringname;//局部变量 //方法体}}其中定义在类中的属性名也就是变......
  • 面向对象的七大原则
    ......
  • 无涯教程-Matplotlib - 面向对象接口
    尽管使用matplotlib.pyplot模块可以轻松快速地生成图,但是建议使用面向对象的方法,因为它可以更好地控制和自定义图。在面向对象的界面中,Pyplot仅用于一些功能,例如图形创建,并且用户显式创建并跟踪图形和轴对象,在此级别上,用户使用Pyplot创建图形,并通过这些图形可以创建一个或多个......
  • C#学习笔记--面向对象三大特征
    C#核心面向对象--封装用程序来抽象现实世界,(万物皆对象)来编程实现功能。三大特性:封装、继承、多态。类与对象声明位置:namespace中样式:class类名{}命名:帕斯卡命名法(首字母大写)实例化对象:根据类来新建一个对象。Personp=newPerson();成员变量声明在类语句块中用来描述......
  • 面向对象测试
    1.下列说法正确的是(B)A、在类方法中可用this来调用本类的类方法B、在类方法中调用本类的类方法时可直接调用C、在类方法中只能调用本类中的类方法D、在类方法中绝对不能调用实例方法A,this是个局部变量,静态类方法中不存在,也没办法调用答案是:A、在类方法中可用this来调用本......
  • 【算法】游戏中的学习,使用c#面向对象特性控制游戏角色移动
    最近,小悦的生活像是一首繁忙的交响曲,每天忙得团团转,虽然她的日程安排得满满当当,但她并未感到充实。相反,她很少有时间陪伴家人,这让她感到有些遗憾。在周五的午后,小悦的哥哥突然打来电话,他的声音里充满了焦虑。“小悦,我有个事情想拜托你。”哥哥的声音传来。小悦不禁有些疑惑,哥哥......