面向对象5

面向对象5

img

子类继承父类,但是只有一个对象

img

Person person=new Man();

有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。

image-20230722121104904

如何才能调用子类特有的属性和方法?

  • 向下转型:使用强制类型转换符。
  • Man m1 =(Man)p2;

image-20230722121352347

p2是由数据类型+地址值,m1改变了数据类型

使用强转时,可能出现ClassCastException的异常。

instanceof关键字的使用

instanceof:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false.。
使用情境:与了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型

如果a instanceof A返回true,而且 a instanceof B也返回true.其中,类B是类A的父类。

==:对于引用数据类型来讲,比较的是两个引用数据类型变量的地址值是否相同

练习;

  1. 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中。编译看左边,运行看右边
  2. 对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量。编译运行都看左边

5.7 Object类的使用

  • Object类是所有Java类的根父类
  • 如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
    public class Person {}
    等价于:
    public class Person extends Object {)
  • 例: method(Object obj){...}//可以接收任何类作为其参数
    Person o=new Person();
    method(o);

3.object类中的功能(属性、方法)就具有通用性。

  • 属性:无
  • 方法:equals() / toString()/ getclass( ) / hashCode() / clone()
    /finalize()/wait()/notify()/notifyAll()

面试题:==和equals()区别

一、回顾==的使用:

== :运算符

1.可以使用在基本数据类型变量和引用数据类型变量中
2.

  • 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)
  • 如果比较的是引用数据类型变量:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体

二、equals()方法的使用:

  1. 是一个方法,而非运算符

  2. 只能适用于引用数据类型

  3. object类中equals()的定义:
    public boolean equals(object obi) {
    return (this obj);
    }
    说明:Object类中定义的equals()和
    的作用是相同的:比较两个对象的地址值是否相同

4.像String、Date、File、包装类等都重写了0bject类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。

image-20230722152802612



object类中toString()的使用:

1.当我们输出一个对象的引用时,实际上就是调用当前对象的toString()

  1. object类中toString()的定义:
public String toString() { 
return getclass().getName() +"@"+ Integer.toHexString(hashCode() );
}

3.像String、 Date、File、包装类等都重写了0bject类中的toString()方法。使得在调用对象的toString()时,返回"实体内容"信息

4.自定义类也可以重写toString()方法,当调用此方法时,返回对象的"实体内容"

直接快捷键alt+ins

package com.xin.OOPTest.demo05;

public class GeometricObject {
    protected String color;
    protected double weight;

    protected GeometricObject() {
        color="white";
        weight=1.0;
    }

    public GeometricObject(String color, double weight) {
        this.color = color;
        this.weight = weight;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }
}

=============
    package com.xin.OOPTest.demo05;

public class Circle extends GeometricObject {
    private double radius;

    public Circle() {
       //super();
        radius=1;
    }

    public Circle(double radius) {
        this.radius = radius;
    }

    public Circle(String color, double weight, double radius) {
        super(color, weight);
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
    }
    //计算圆的面积
    public double findArea(){
        return 3.14*radius*radius;
    }
    /**
     * 比较两个圆的半径是否相等,如相等,返回true。
     */
    @Override
    public boolean equals(Object obj) {
        if (this==obj){
            return true;
        }if (obj instanceof Circle){
            Circle c=(Circle) obj;
            return this.radius==c.radius;
        }
        return false;
    }

    /**
     * 重写后本来返回对象地址值,现在返回对象的半径
     * @return 对象的半径
     */
    @Override
    public String toString() {
        return "Circle{" +
                "radius=" + radius +
                '}';
    }
}

===============
    package com.xin.OOPTest.demo05;
/*
写一个测试类,创建两个Circle对象,判断其颜色是否相等;
利用equals方法判断其半径是否相等;利用toString()方法输出其半径。

 */
public class CircleTest {
    public static void main(String[] args) {
        Circle circle1 = new Circle(2.3);
        Circle circle2=new Circle("white",2.3,2.0);
        System.out.println("颜色是否相等:" + circle2.color.equals(circle1.color));
        System.out.println("半径是否相等:" + circle2.equals(circle1));
        System.out.println(circle1);//Circle{radius=2.3}
        System.out.println(circle2.toString());//Circle{radius=2.0}
    }
}

java中的JUnit单元测试

步骤:
1.选中当前工程–右键选择:build path - add libraries - JUnit 4 - 下一步

2.创建Java类,进行单元测试。
此时的Java类要求:@此类是public的②此类提供公共的无参的构造器

3.此类中声明单元测试方法。

此时的单元测试方法:方法的权限是public,没有返回值,没有形参

4.此单元测试方法上需要声明注解:@Test,并在单元测试类中导入:import org.junit.Test;

5.声明好单元测试方法以后,就可以在方法体内测试相关的代码。
6.写完代码以后,左键双击单元测试方法名,右键:run as - JUnit Test

说明;
1.如果执行结果没有任何异常:绿条

2.如果执行结果出现异常:红条


5.8 包装类(Wrapper)的使用

image-20230722184355800

image-20230722185110662

包装类的使用:

1.java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征

包装类--->基本数据类型:调用包装类Xxx的XxxValue()

package com.xin.OOPTest.demo05;

public class Day72200 {


    public void testTest1() {
        int a1 = 1;
        int a2 = 1;
        System.out.println(a1 == a2);
    }

}
============
    package com.xin.OOPTest.demo05;

import junit.framework.TestCase;

public class Day72200Test extends TestCase {



    public void testTest2() {
        int num=10;
        Integer a=new Integer(num);
        System.out.println(a.toString());
        Integer b=new Integer("163854");
        System.out.println(b.toString());
        Boolean c=new Boolean("true123");//false
        System.out.println(c);
        System.out.println("===============");
        int b1=b.intValue();
        System.out.println(b1);
        Integer z=123;//自动装箱
        int z1=z;//自动拆箱
        System.out.println("===========");
        //基本数据类型、包装类--->String类型
        String zz=z1+" ";//连接运算
        float f1=12.3f;
        String str1=String.valueOf(f1);//调用String的valueof(XXX XXX)
        // String类型--->基本数据类型、包装类:调用包装类的parseXxx()
        int s=Integer.parseInt("163854");

    }
}
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);//false
// Integer内部定义了IntegerCache结构,Integercache中定义了Integer[]保存了从-128~127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在//-128~127范围内时,可以直接使用数组中的元素,不用再去new了。
Integer m = 1;
Integer n = 1;
System.out.println(m == n); //true
Integer x = 128;//相当于new了一个Integer对象
Integer y = 128;//相当于new了一个Integer对象System.out.println(x == y);//false

数组也作为Object类的子类出现,可以调用Object类中声明的方法

package com.xin.OOPTest.demo06;

import java.util.Objects;

public class Person {
    int age;
    String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

 //   @Override
//    public boolean equals(Object o) {
//        if (this == o) return true;
//        if (o == null || getClass() != o.getClass()) return false;
//        Person person = (Person) o;
//        return age == person.age && Objects.equals(name, person.name);
//    }

//    public boolean equals(Object o) {
//        if (this==o){
//            return true;
//        }
//        if (o instanceof Person){
//            Person a=(Person) o;
//            return this.age==a.age&&this.name.equals(a.name);
//        }
//        return false;
//    }
}
=============
    package com.xin.OOPTest.demo06;

public class Man extends Person {
//    int age;
//    String name;


    public Man(int age, String name) {
        super(age, name);
    }
    public boolean equals(Object o) {
        if (this==o){
            return true;
        }
        if (o instanceof Man){
            Man a=(Man) o;
            return this.age==a.age&&this.name.equals(a.name);
        }
        return false;
    }
}
============
    package com.xin.OOPTest.demo06;

public class Day72300 {
    public static void main(String[] args) {
        Person abc = new Person(5, "abc");
        Man abc1 = new Man(5, "abc");
        boolean equals = abc.equals(abc1);
        System.out.println(abc.equals(abc1));//对Person重写是true,对Man重写是false
        System.out.println(abc1.getClass());//class com.xin.OOPTest.demo06.Man
        System.out.println(abc.getClass());//class com.xin.OOPTest.demo06.Person
    }
}


static关键字的使用

  1. static:静态的

  2. static可以用来修饰:属性、方法、代码块、内部类

  3. 使用static修饰属性:静态变量(类变量)
    3.1属性,按是否使用static修饰,又分为:静态属性vs非静态属性(实例变量)

    • 实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
    • 静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。

    3.2 static修饰属性的其他说明:

    • 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用

    • 静态变量的加载要早于对象的创建。

    • 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。

    • 类变量 实例变量
      yes no
      对象 yes yes

​ 3.3 静态属性举例:System.out; Math.PI;

类变量与实例变量的解析

image-20230723114649545

4.使用static修饰方法:静态方法

  • 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用
类方法 实例方法
yes no
对象 yes yes
  • 静态方法中,只能调用静态的方法或属性
    非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
  1. static注意点:
    5.1 在静态的方法内,不能使用this关键字、super关键字
    5.2 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。

  2. 开发中,如何确定一个属性是否要声明为static的?

  • 属性是可以被多个对象所共享的,不会随着对象的不同而不同的。
  • 类中的常量也常常声明为static

​ 开发中,如何确定一个方法是否要声明为static的?

  • 操作静态属性的方法,通常设置为static的
  • 工具类中的方法,习惯上声明为static的。比如:Math、Arrays、collections
package com.xin.OOPTest.demo06;

public class Circle {
    public static void main(String[] args) {
        Circle1 circle1 = new Circle1();
        Circle1 circle2 = new Circle1();
        System.out.println(circle1.getId());//1001
        System.out.println(circle2.getId());//1002
        System.out.println(circle1.getTotal());//2
        System.out.println(circle2.getTotal());//2
    }
}
class Circle1{
    private double radius;
    private int id;
    private static int total;//记录创建圆的个数
    private static int init=1001;//static声明的属性被所有对象所共享,由此可以使不同对象产生关联

    public Circle1() {
        total++;
        id=init++;
    }

    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
    }

    public int getId() {
        return id;
    }

    public static int getTotal() {
        return total;
    }

    public static void setInit(int init) {
        Circle1.init = init;
    }
}

单例(Singleton)设计模式

  • 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模免去我们自己再思考和摸索。式就像是经典的棋谱,不同的棋局,我们用不同的谱,"套路"
  • 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
  1. 创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
  2. 结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
  3. 行为型模式,共11种∶策略模式、模板方法模式、观察者模式、迭代子模式、责任键模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器棋式
package com.xin.OOPTest.demo06;
/*
单例设计模式
1.所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。
2.如何实现?

 */
public class SingletonTest1 {
    public static void main(String[] args) {
        Bank bank = Bank.getInstance();//1.得到唯一一个静态对象,饿汉式
        Bank1 bank1 = Bank1.getInstance1();//2.懒汉式
    }
}

/**
 * 饿汉式创造唯一对象
 */
class Bank{
    //1.私有化类的构造器
    private Bank() {

    }
    //2.内部创建类的对象(静态)
    private static Bank instance=new Bank();
    //3.提供公共的(静态)方法,返回类的对象
    public static Bank getInstance(){
        return instance;
    }
}
/**
 * 懒汉式创造唯一对象
 */
class Bank1{
    //1.私有化类的构造器
    private Bank1() {

    }
    //2.内部创建类的对象(静态),没有初始化
    private static Bank1 instance1=null;
    //3.提供公共的(静态)方法,返回类的对象
    public static Bank1 getInstance1(){
        if (instance1==null){
            instance1=new Bank1();
        }
        return instance1;
    }
}

2.如何实现?
饿汉式 vs 懒汉式

3.区分饿汉式和懒汉式
饿汉式:

  • 坏处:对象加载时间过长。
  • 好处:饿汉式是线程安全的

懒汉式:

  • 好处:延迟对象的创建。
  • 目前的写法坏处:线程不安全。--->到多线程内容时,再修改

单例(Singleton)设计模式-应用场景

  1. 网站的计数器,一般也是单例模式实现,否则难以同步。
  2. 应用程序的日志应用,一般都使用单例模式实现,这一放足田丁兴子的口心文件一直处于打开状态,因为只能有一个实例去操作,否则内容个好追加。
  3. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据厍资源。
  4. 项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。
  5. Application也是单例的典型应用
  6. Windows的Task Manager (任务管理器)就是很典型的单例模式
  7. Windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

main()方法的使用说明:

  1. main(()方法作为程序的入口
  2. main()方法也是一个普通的静态方法
  3. main()方法可以作为我们与控制台交互的方式。(之前:使用Scanner)

类的成员之四:代码块(或初始化块)

  1. 代码块的作用:用来初始化类、对象

  2. 代码块如果有修饰的话,只能使用static.

  3. 分类:静态代码块vs非静态代码块

  4. 静态代码块

    • 内部可以有输出语句
    • 随着类的加载而执行,而且只执行一次
    • 作用:初始化类的信息
    • 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
    • 静态代码块的执行要优先于非静态代码块的执行
    • 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
  5. 非静态代码块

  • 内部可以有输出语句
  • 随着对象的创建而执行
  • 每创建一个对象,就执行一次非静态代码块
  • 作用:可以在创建对象时,对对象的属性等进行初始化
  • 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
  • 非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法
package com.xin.OOPTest.demo06;

public class BlockTest {
    public static void main(String[] args) {
        String desc = Person1.desc;//hello.
        Person1 person1 = new Person1();//hello00000.

    }
}
class Person1{
    //属性
    String name;
    static String desc="晚上开会艰苦";
    //构造器
    public Person1() {
    }
    //静态代码块
    static {
        System.out.println("hello.");
    }
    //非静态代码块
    {
        System.out.println("hello00000.");
    }
}

对属性可以赋值的位置:

①默认初始化
②显式初始化/在代码块中赋值(按照位置顺序)

③构造器中初始化
④有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值

先后循序例子

  1. Root的静态初始化块
  2. Mid的静态初始化块
  3. Leaf的静态初始化块
  4. Root的普通初始化块
  5. Root的无参数的构造器
  6. Mid的普通初始化块
  7. Mid的无参数的构造器
  8. Mid的带参数构造器,其参数值:尚硅谷
  9. Leaf的普通初始化块
  10. Leaf的构造器

总结:由父及子,静态先行

package com.xin.OOPTest.demo06;

public class BlockTest {
    public static void main(String[] args) {
        String desc = Person1.desc;//hello.
        Person1 person1 = new Person1();//hello00000.

    }
}
class Person1{
    //属性
    String name;
    static String desc="晚上开会艰苦";
    //构造器
    public Person1() {
    }
    //静态代码块
    static {
        System.out.println("hello.");
    }
    //非静态代码块
    {
        System.out.println("hello00000.");
    }
}


final:最终的

  1. final可以用来修饰的结构:类、方法、变量

  2. final用来修饰一个类:此类不能被其他类所继承。
    比如:String类、System类、StringBuffer类

  3. final 用来修饰方法:表明此方法不可以被重写.比如:Object类中getclass();

  4. final用来修饰变量:此时的"变量"就称为是一个常量

    • final修饰属性:可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
    • final修饰局部变量:
      尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦以后,就只能在方法体内使用此形参,但不能进行重新赋值
  5. static final用来修饰属性:全局常量


小结:一叶知秋

  • publicstaticvoidmain(String[ ] args)
  • 权限修饰符: private缺省protected pubilc ---->封装性
  • 修饰符: static \ final \ abstract \native 可以用来修饰方法
  • 返回值类型:无返回值/有返回值-->return
  • 方法名:需要满足标识符命名的规则、规范;"见名知意"
  • 形参列表:重载vs重写;参数的值传递机制;体现对象的多态性
  • 方法体:来体现方法的功能
posted @   新至所向  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示