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

相关文章

springboot集成easypoi导出word换行处理过程

《springboot集成easypoi导出word换行处理过程》SpringBoot集成Easypoi导出Word时,换行符n失效显示为空格,解决方法包括生成段落或替换模板中n为回车,同时需确... 目录项目场景问题描述解决方案第一种:生成段落的方式第二种:替换模板的情况,换行符替换成回车总结项目场景s

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

SpringBoot中@Value注入静态变量方式

《SpringBoot中@Value注入静态变量方式》SpringBoot中静态变量无法直接用@Value注入,需通过setter方法,@Value(${})从属性文件获取值,@Value(#{})用... 目录项目场景解决方案注解说明1、@Value("${}")使用示例2、@Value("#{}"php

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏