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编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J

Java中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis