面向对象5
面向对象5
子类继承父类,但是只有一个对象
Person person=new Man();
有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。
如何才能调用子类特有的属性和方法?
- 向下转型:使用强制类型转换符。
- Man m1 =(Man)p2;
p2是由数据类型+地址值,m1改变了数据类型
使用强转时,可能出现ClassCastException的异常。
instanceof关键字的使用
instanceof:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false.。
使用情境:与了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型
如果a instanceof A返回true,而且 a instanceof B也返回true.其中,类B是类A的父类。
==:对于引用数据类型来讲,比较的是两个引用数据类型变量的地址值是否相同
练习;
- 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中。编译看左边,运行看右边
- 对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量。编译运行都看左边
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()方法的使用:
-
是一个方法,而非运算符
-
只能适用于引用数据类型
-
object类中equals()的定义:
public boolean equals(object obi) {
return (this obj);
}
说明:Object类中定义的equals()和的作用是相同的:比较两个对象的地址值是否相同
4.像String、Date、File、包装类等都重写了0bject类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。
object类中toString()的使用:
1.当我们输出一个对象的引用时,实际上就是调用当前对象的toString()
- 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)的使用
包装类的使用:
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关键字的使用
-
static:静态的
-
static可以用来修饰:属性、方法、代码块、内部类
-
使用static修饰属性:静态变量(类变量)
3.1属性,按是否使用static修饰,又分为:静态属性vs非静态属性(实例变量)- 实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
- 静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。
3.2 static修饰属性的其他说明:
-
静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用
-
静态变量的加载要早于对象的创建。
-
由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。
-
类变量 实例变量 类 yes no 对象 yes yes
3.3 静态属性举例:System.out; Math.PI;
类变量与实例变量的解析
4.使用static修饰方法:静态方法
- 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用
类方法 | 实例方法 | |
---|---|---|
类 | yes | no |
对象 | yes | yes |
- 静态方法中,只能调用静态的方法或属性
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
-
static注意点:
5.1 在静态的方法内,不能使用this关键字、super关键字
5.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操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
- 创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
- 结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
- 行为型模式,共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)设计模式-应用场景
- 网站的计数器,一般也是单例模式实现,否则难以同步。
- 应用程序的日志应用,一般都使用单例模式实现,这一放足田丁兴子的口心文件一直处于打开状态,因为只能有一个实例去操作,否则内容个好追加。
- 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据厍资源。
- 项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。
- Application也是单例的典型应用
- Windows的Task Manager (任务管理器)就是很典型的单例模式
- Windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
main()方法的使用说明:
- main(()方法作为程序的入口
- main()方法也是一个普通的静态方法
- main()方法可以作为我们与控制台交互的方式。(之前:使用Scanner)
类的成员之四:代码块(或初始化块)
-
代码块的作用:用来初始化类、对象
-
代码块如果有修饰的话,只能使用static.
-
分类:静态代码块vs非静态代码块
-
静态代码块
- 内部可以有输出语句
- 随着类的加载而执行,而且只执行一次
- 作用:初始化类的信息
- 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
- 静态代码块的执行要优先于非静态代码块的执行
- 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
-
非静态代码块
- 内部可以有输出语句
- 随着对象的创建而执行
- 每创建一个对象,就执行一次非静态代码块
- 作用:可以在创建对象时,对对象的属性等进行初始化
- 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
- 非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法
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.");
}
}
对属性可以赋值的位置:
①默认初始化
②显式初始化/在代码块中赋值(按照位置顺序)
③构造器中初始化
④有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值
先后循序例子
- Root的静态初始化块
- Mid的静态初始化块
- Leaf的静态初始化块
- Root的普通初始化块
- Root的无参数的构造器
- Mid的普通初始化块
- Mid的无参数的构造器
- Mid的带参数构造器,其参数值:尚硅谷
- Leaf的普通初始化块
- 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:最终的
-
final可以用来修饰的结构:类、方法、变量
-
final用来修饰一个类:此类不能被其他类所继承。
比如:String类、System类、StringBuffer类 -
final 用来修饰方法:表明此方法不可以被重写.比如:Object类中getclass();
-
final用来修饰变量:此时的"变量"就称为是一个常量
- final修饰属性:可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
- final修饰局部变量:
尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦以后,就只能在方法体内使用此形参,但不能进行重新赋值
-
static final用来修饰属性:全局常量
小结:一叶知秋
- publicstaticvoidmain(String[ ] args)
- 权限修饰符: private缺省protected pubilc ---->封装性
- 修饰符: static \ final \ abstract \native 可以用来修饰方法
- 返回值类型:无返回值/有返回值-->return
- 方法名:需要满足标识符命名的规则、规范;"见名知意"
- 形参列表:重载vs重写;参数的值传递机制;体现对象的多态性
- 方法体:来体现方法的功能
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?