JAVA基础:封装、继承和多态(详讲)

2024-09-03 17:28

本文主要是介绍JAVA基础:封装、继承和多态(详讲),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 封装

  • 面向对象的三大特征 : 封装, 继承, 多态 。

封装可以从三个层面理解

  1. 将属性和方法组合在一起(封闭在一起)

  2. 将属性隐藏起来, 对外提供可以间接操作属性的方法。(提高程序设计安全性)

    目前我们都是属性私有化, 并提供与之对应的get和set方法

  3. 封装应用工具,为其他的程序员提供功能帮助。

属性的get和set方法

  • 这是一种封装设计

  • 但不是语法要求,是一种约定俗称。

  • 一般的要求是,属性私有, 其对应的get和set方法就是在get和set后面连接属性名

class Goods{private String gname ;private String kind ;private int price ;private int count ;//可以间接的为kind赋值public void setKind(String kind){this.kind = kind ;}//可以间接获得kind属性值public String getKind(){return kind ;}public void setGname(String gname){this.gname = gname ;}public String getGname(){return gname ;}}class Test{main(){Goods g = new Goods();//g.gname ; 无法直接访问//g.kind ; 无法直接访问g.setGname("可乐");// g.gname = "" ;print( g.getGname() ) ; // print( g.gname ) ;   getGname(g)}
}

特殊的get和set方法

  • get和set方法的写法不一定完全一致。

class A{private int age ;public void setAge(String age){this.age = Integer.parseInt(age) ;}
}

  • boolean类型的属性,其get方法有些特别,是以is开头

class A{private boolean flag ;public void setFlag(boolean flag){this.flag = flag ;}public boolean isFlag(){return flag ;}
}

2 继承

需要两个类才能实现继承的效果。 比如:类A 继承 类B

  • A类 称为 子类 , 衍生类,派生类

  • B类 称为 父类,基类,超类

继承的作用

  1. 子类自动的拥有父类的所有属性和方法 (父类编写,子类不需要再编写) 。 代码复用

    目前私有的属性和方法无法访问。

  2. 多态的基础。

继承语法

  • 先定义父类 (单独的类)

  • 在定义子类的同时,实现与父类的继承关系

class B{String name ;public void t1() {}
}class A extends B{//String name ;//public void t1() {}
}A a = new A();
a.name = "zs" ;
a.t1();

继承特点

  1. 继承具有传递性

    A extends B extends C

    A类中,既有B类的内容,又有C类的内容

  2. 基础具有不可逆性

    A extends B

    A类中,有B类的内容

    但B类中没有A类的内容。

  3. Java只支持单继承 (C++支持多继承)

    一个类只能继承一个父类。

    但可以连续继承 A extends B extends C

    A extends B A extends C 不可以的

3 子类对象的创建过程

  • 不存在父类对象这个概念

class A{String name ;public void t1(){}
}
class B extends A{int age ;public void t2(){}
}new A(); //不算父类对象
new B() ;//这就是我们所说的子类对象

 

  • 尽管B对象中的name属性,是从A类中继承而来的

  • 但使用过程中,直接通过name名称就可以访问到。

  • 可以使用JOL工具来查看内存结果

4 super关键字

可以指定父类的内容 (属性,方法,构造方法)

一般情况下,在子类中,可以默认指定父类的内容。

  • 变量访问的顺序: 局部变量->类变量->父类变量->报错

class B{String name1 ;
}
class A extends B{String name1 ;public void t1(){String name1 ;print(name) ;}
}

但有些情况必须使用super来指定父类的内容

  1. 子类中写了与父类中同名的属性和方法 (重写)

  2. 在子类的构造方法中,指定要调用的父类的构造方法

    在创建子类对象时,不仅仅子类对象的构造方法会被调用,父类的构造方法也会被调用

    是在子类构造方法的第一行被调用的。 (先调用子类的构造器,先执行完父类的构造器)

    默认会在子类构造方法的第一行,执行super(),表示调用父类的无参构造器

class A{int a ;int b ;public A(int a , int b){this.a = a ;this.b = b ;}public void A(){}
}class B extends A{int c ;int d ;public B(){}public B(int c , int d){}public B(int a , int b , int c, int d){//想将a和b交给父类的构造器//super()super(a,b);this.c = c ;this.d = d ;}
}B b =  new B(10,20,30,40);

this和super关键字

  • 在使用上,this和super特点相似

  • 但本质上完全不同

  • this的本质,是一个参数变量,存储的是当前方法所属对应的地址。

  • super的本质,就是一个关键字,用来指定父类的内容。这个指定效果在编译后就没有了。

    而this是在运行时有所应用的。

5 多态

事物的多种表现形态。

人有多种表现形态:学生,老师,警察,医生等。

作用:在封装时,可以更灵活的切换具体的执行功能

多态的实现过程:

  1. 继承

  2. 重写

  3. 上转型

5.1 重写

发生在子父类关系中。

在子类中,重新编写与父类相同的属性和方法。 称为方法重写,属性重写

属性重写

  • 只需要在子类中定义父类同名的属性即可, 类型可以不同

  • 使用上: 类的内部的使用super指定使用的是子类的属性还是父类的属性

    类的外部使用时,默认使用的是子类重写的属性

    只有在上转型时,可以使用父类的属性。

    属性的重写又称为属性的隐藏。

方法重写

  • 子类中的方法与父类中的方法名称相同,参数列表相同,执行不同的操作

  • 一般情况下 访问权限,返回类型,异常声明 都建议相同。

  • 实际上

    • 子类重写方法的访问权限要大于等于父类方法的访问权限。

    • 子类重写方法的返回类型要小于等于父类方法的返回类型 (基于子父关系)

class A{}
class A1 extends A{}
class A2 extends A1{}class B1{public A1 t1(){}
}
class B2 extends B1{public A2 t1(){}
}

  子类重写方法的异常声明类型或个数 小于等于父类方法

class E41 extends E4{}
class B1{public A1 t1()throws E1,E2,E3,E41{}
}
class B2 extends B1{public A2 t1()throws E4{}
}

  • 关于修饰符

    • static关键字修饰的方法不存在重写(概念)

    • final关键字修饰的方法不能被重写

    • abstract关键字修饰的方法必须被重写

  • 使用上:类的内部可以使用super指定父类的方法

    类的外部,只能使用子类重写的方法,无法使用从父类继承的方法,即使上转型也不行

    方法的重写又称为方法的覆盖

5.2 上转型

将子类对象的地址存储在父类型的变量中 , 将子类对象当成父类型对象来用(本质还是子类对象)

class A{}
class B extends A{}B b = new B();
A a = b ;
----------
A a = new B();

 

  • 使用时,因为用的是A类型的变量, 所以以为用的是A类型的对象,所以只能用A类型中才有的属性和方法

  • 但实际上, a变量中存储的是B类型的对象, 所以调用的方法都是B类型的方法

  • 由于B类型的对象中,既包含B的属性,也包含父类A中的属性, 而使用时又以为使用的是A类型的对象,所以属性调用的就是从A中继承的属性,也就是父类的属性

5.3 下转型

在下转型之前,一定先存在上转型

所谓的下转型,是将之前因为上转型,存储在父类型变量中的子类型对象的地址重新存储在子类型的变量中。类似与强转一样,需要使用()来指定下转的类型。

class A{}
class B extends A{}A a= new B();
B b = (B)a ;

几种情况:

  1. 两个类型不存在子父关系,无法下转型(不能强转),此时会出现语法编译错误

User u = new User();
Phone p = (Phone)u ;  //语法错误

 2.两个类型存在子父关系,但本质类型不相同。 此时语法编译通过,运行出错

class A{}
class A1 extends A{}
class A2 extends A{}A a = new A1();
A2 a2 = (A)a ;  //运行错误 , 类型转化错误

 3.两个类型存在子父关系,本质类型也是相同的。此时可以正常编译运行

class A{}
class A1 extends A{}
class A2 extends A{}A a = new A1();
A1 a1 = (A)a ;

6 final关键字

final关键字可以修饰变量, 方法 和 类

final修饰变量

  • 可以是局部变量,也可以是属性变量,也可以是静态变量

  • 表示常量,只能被赋值一次,之后不能被改变。

class A{final static int a = 10;final int b = 20;public void t1(final int d){final int c = 30;}
}

常量变量和常量值

  • 使用final修饰的变量,就成为常量变量

  • 在为变量赋值时,=右边那个具体的数值,就称为常量值 10 , 20 , "abc" , 'a' , true

final修饰方法

称为最终方法, 不能被重写

class A{public void t1(){}public final void t2(){}
}class B extends A{public void t1(){}public void t2(){} //错误
}

final修饰类

称为最终类,不能被继承

7 Object类

是所有类的终极父类。

无论是jdk自带的类或数组,还是我们自定义的类,最终都会继承Object这个父类

而且不需要写出来。

Object类中的方法所有的类都具备

  • getClass() 后面反射时会讲

  • clone() 后面讲接口和异常时会讲

  • hashCode() 后面讲集合的时候会讲

  • finalize() 后面讲异常时会讲

  • wait() , wait(long) , wait(...) , notify() , notifyAll() 后面讲线程会讲

  • toString() 返回一个字符串,用来描述当前对象

  • equals() 用来比较当前对象与另一个对象是否相等

String toString()方法

  • 返回一个字符串,代表当前对象的一个文字描述

  • 默认toString方法返回的内容包括对象的类型及对象的地址

  • 在打印对象时,会默认打印对象的toString方法的返回值。

boolean equals(Object obj) 方法

  • equals用来比较两个对象是否相等。通过源码可知, 使用的是 == 比较。

    • == 可以比较基本类型 , 也可以比较引用类型。 比较基本类型比的是值,比较引用类型比较的是地址

    • equals只能比较引用类型,默认比较的是地址,但可以通过重写,改成比较内容. 像String就重写了equals方法,改为比较内容了

  • 比较哪两个对象是否相等呢?

    • 一个是this这个对象

    • 还有一个是以参数传递过来的对象 obj

    • obj的本质也是当前类型的对象。 目的就是比较两个相同类型的对象是否相等

    • 可以通过强转,将obj还原成最开始的类型, 并完成this与obj的属性内容比较

class G{String name = "zs" ;int age = 18 ;public String toString(){return "my name is "+ name + ", my age is " + age ;}public boolean equals(Object obj){if( this == obj){return true ;}G g = (G)obj ;if(this.name.equals(g.name) && this.age == g.age){return true ;}else{return false ;}}}


 

这篇关于JAVA基础:封装、继承和多态(详讲)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1133569

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2