Java---第六章(封装,包,继承)


在这里插入图片描述

一 封装(Encapsulation)

封装的介绍

什么是封装?

封装就是将类的部分属性和方法隐藏起来,不允许外部程序直接访问,只能通过该类公开提供的方法来访问类中定义的属性和方法,封装是面向对象的三大特征之一。

如何使用封装?
示例:
创建一个Person类

public class Person {
    
    
    public String name;//姓名
    public int age;//年龄
    public String secret;//秘密
    public Person(String name,int age,String secret){
    
    
        this.name=name;
        this.age=age;
        this.secret=secret;
    }
}

修改属性的可见性:将类中定义的所有属性全部修改为private修饰

public class Person {
    
    
    private String name;//姓名
    private int age;//年龄
    private String secret;//秘密
    public Person(String name,int age,String secret){
    
    
        this.name=name;
        this.age=age;
        this.secret=secret;
    }
}

再去直接修改年龄值,就会报错

 public class PersonTest {
    
    
    public static void main(String[] args){
    
    
        Person p1 = new Person("刘德华",54,"双重人格");
        p1.age=30;//报错
    }
}

创建公开的getter/setter方法:用于读取/修改属性值

public class Person {
    
    
    private String name;//姓名
    private int age;//年龄
    private String secret;//秘密
    public Person(String name,int age,String secret) {
    
    
        this.name=name;
        this.age=age;
        this.secret=secret;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String getSecret() {
    
    
        return secret;
    }

    public void setSecret(String secret) {
    
    
        this.secret = secret;
    }
}
 public class PersonTest {
    
    
    public static void main(String[] args){
    
    
        Person p1 = new Person("刘德华",54,"双重人格");
        p1.setName("伍六七");
        String name = p1.getName();
    }
}

在getter/setter方法中加入控制语句:用于对属性值的合法性校验
在类中,对应的属性进行增加校验语句

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        if (age < 0) {
    
    
            System.out.println("年龄不合法,必须大于0");
        } else {
    
    
            this.age = age;
        }
    }

在方法中

 public class PersonTest {
    
    
    public static void main(String[] args){
    
    
        Person p1 = new Person("刘德华",54,"双重人格");
        p1.setAge(-1);
        //输出
        //年龄不合法,必须大于0
    }
}

为什么要使用封装?

  • 封装提高了代码的重用性。
    因为封装会提供对外访问的公开的方法,而方法可以重用,因此封装提高了代码的重用性。
  • 封装提高了代码的可维护性。
    修改代码时,只需要修改部分代码,但不会影响其他代码。
    比如:年龄在设计时只考虑了负数的情况,没有考虑到实际生活中的情况,人的年龄一般不会超过200岁,因此还需要加上一层验证
    public void setAge(int age) {
    
    
        if (age < 0 || age > 200) {
    
    
            System.out.println("年龄不合法,必须大于0并且小于200");
        } else {
    
    
            this.age = age;
        }
    }
  • 封装隐藏了类的具体实现细节,保护了代码实现逻辑。

二 包(Package)

包的介绍

什么是包?
包时Java中的一个专业词汇,包的本质就是一个文件夹。

为什么要使用包?

  • 包可以对我们所写的类,进行分类。
  • 可以防止命名冲突
  • 访问权限控制

如何创建包?
语法:

package 包名;

在这里插入图片描述
其中,com,ly,chat11分别为一个文件夹

在这里插入图片描述

包名的命名规范:

  • 包名一般由小写字母和数字组成,每个包之间用’.‘隔开,换言之,每出现一个’.',就是一个包。
  • 包名一般含有前缀。
  • 个人/组织通常是org.姓名
  • 公司通常是com.公司名称简称或者cn.公司名称简称
  • 如果一个类中有包的定义,那么这个类的第一行有效代码一定会是包的定义

如何引入包?
为了使用不在同一包中的类,需要再Java程序中使用import关键字引入这个类
语法:

import 包名.类名;
package com.ly.chat11;
//类的全限定名:包名+'.'+类名
import java.util.Scanner;//告诉JVM,到Java.util包下去找一个名为Scanner的类 

public class User {
    
    
    public static void main(String[] args){
    
    
        Scanner sc = new Scanner(System.in);
    }
}

为什么要引入包?

因为JVM只能识别当前包下所有的类,如果要使用当前包之外的其他包的类,那必须告诉JVM,使用的是哪一个包中的哪一个类。

一个类同时引用两个来自不同包的同名类,必须通过完整类名(类的全限定名)来区分
在这里插入图片描述
在这里插入图片描述

常用包的说明:

Java.lang 包

属于Java语言的开发包,该包中的类可以直接拿来使用,而不需要引入包。因为JVM会自动引入
比如:我们经常使用的System,String,Math

Java.util 包

属于Java提供的一些使用类以及工具类。
比如:我们经常使用的Scanner

三 访问修饰符

访问修饰符的介绍

概念:

访问修饰符就是控制访问权限的修饰符号

类的访问修饰符:
类的访问修饰符只有两种:

  • public修饰符
  • 默认修饰符(不写修饰符就是默认)

public修饰符修饰类表示类可以公开访问。
默认修饰符修饰类,表示该类只能在同一个包中访问

类成员访问修饰符:
类成员包括了成员属性和成员方法。
类成员访问修饰符换言之就是成员属性和成员方法的访问修饰符。
在这里插入图片描述

四 static内存

static修饰符应用范围:
static修饰符只能用来修饰类中定义的成员变量,成员方法,代码块以及内部类(内部类有专门的章节进行讲解)

static修饰成员变量:
static修饰成员变量称之为类变量。属于该类所有成员共享

假如country初识值为:“中国”,修改之后为“日本”,那么再去调用值就为“日本”
不是成员变量,不会随着成员而改变

如果类变量是公开的,那么可以使用类名.变量名直接访问该类变量

static修饰代码块:

static修饰代码块称为静态代码块,在JVM第一次记载该类时执行。
因此,静态代码块只能够被执行一次,通常用于一些系统设置场景。

        static {
    
    
            
        }

五 继承(Inheritance)

继承的介绍

概念:
继承的概念简单而强大,当你要创建一个新类,并且已经有一个包含所需代码的类时,可以从现有类中派生出来新类。这样,你可以重用现有类的字段和方法,而不必自己编写(调试)它们。

子类从其父类继承所有成员(字段,方法和嵌套类),构造方法不是成员,因此他们不会被子类继承,但是可以从子类中调用父类的构造方法。

从一个类派生出来的类叫作子类(也可以是派生类,拓展类或者子类),派生子类的类叫作超类(也称为基类或者父类

继承也是面向对象的三大特征之一。

如何使用继承?
语法:

publis class 子类名 extends 父类名{
    
    

}

示例:

public class Person{
    
    
    public String name;
    public String sex;
    public int age;
    public void eat(){
    
    
        System.out.println("吃饭");
    }
}
public class PersonTest extends Person{
    
    
    public void show(){
    
    
        System.out.println(name);
        //本类中未定义name变量,但却可以使用,说明name变量是从父类中继承过来的
    }
}

继承的属性和方法:

无论子类在什么包中,子类会继承父类所有公开的和受保护的成员(包括字段和方法)。如果子类和父类在同一个包里,子类也会继承父类中受包保护的成员。

子类不会继承父类中定义的私有成员,尽管如此,如果父类中有提供公开或者受保护的访问该字段的方法,这些方法也能在子类中被使用

重复性代码:

public class Person{
    
    
    public String name;
    public String sex;
    public int age;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public String getSex() {
    
    
        return sex;
    }

    public void setSex(String sex) {
    
    
        this.sex = sex;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public void eat(){
    
    
        System.out.println("吃饭");
    }
}

医生特有类:

public class Doctor extends Person{
    
    
    private String professional;

    public String getProfessional() {
    
    
        return professional;
    }

    public void setProfessional(String professional) {
    
    
        this.professional = professional;
    }

    public void cure(){
    
    
        System.out.println("治病");
    }

}

测试,创建对象:

public class PersonTest{
    
    
    public static void main(String[] args) {
    
    
        Doctor d =new Doctor();
        d.setName("Miss");
        d.setSex("女");
        d.setAge(19);
        d.setProfessional("临床");

        //优化之后
        Person p1 = new Doctor();
        p1.setName("Miss");
        p1.setSex("女");
        p1.setAge(19);
        p1.setProfessional("临床");//报错,因为该类不在Person里
        //但是我们可以使用强制类型转换
        ((Doctor)p1).setProfessional("临床");
    }
}

子类和父类的关系是is-a关系,表示一个
如果一个对象赋值给其父类引用,此时想要调用该对象的特有的方法,必须要对其进行强制类型转换

六 方法重写(Override)

方法重写的介绍

子类中的一个成员方法与父类中的成员方法有相同的签名(方法名加上参数数量和参数类型)和返回值类型的实例方法重写了父类的方法

如何使用方法重写:

子类重写方法的能力使类可以从行为“足够近”的父类继承,然后根据需要修改行为,重写方法与被重写的方法具有相同的名称,数量和参数类型,并且返回类型相同,重写方法还可以返回重写方法返回的类型的子类型,此子类型称为协变返回类型。

举例:

    public Number getScore(){
    
    
        return 0;
    }

子类重写父类的方法时,返回值类型可以是父类方法的返回值类型的子类

重写方法时的访问修饰符级别不能降低

    public Integer getScore(){
    
    
        return 90;
    }

重写方法时,你可以需要使用 @override 来注解,该注释指示编译器你打算重写父类中的方法。如果由于某种原因,编译器检测到该方法在父类中不存在,则它将生成错误。

之前我们所学习的数字包括byte short int long float double类型
那么他们所对应的number的子类: Byte Short Integer Long Float Double

七 super 关键字

概念:

如果子类的构造方法没有明确调用父类的构造方法,Java编译器会自动插入一个父类无参构造的调用。如果父类没有无参构造,你将得到一个编译时错误。
object类有一个无参构造,因此,如果object类是唯一的父类,这就没有问题。

示例一:子类和父类中都没有定义构造方法
父类:

public class Person{
    
    
    public String name;
    public Person(){
    
    
		super();
    }
    public Number getScore(){
    
    
        return 0;
    }
    
    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }
}

子类:

public class Doctor extends Person{
    
    
    private String professional;
    //如果一个类中没有定义构造方法,那么编译器将会给该类插入一个无参构造方法
    public Doctor(){
    
    
        super();//如果子类构造方法中没有明显调用父类的构造方法,那么编译器会
        //自动插入一个父类的无参构造的调用
    }

    public String getProfessional() {
    
    
        return professional;
    }
    
    public void setProfessional(String professional) {
    
    
        this.professional = professional;
    }

    public void cure(){
    
    
        System.out.println("治病");
    }

}

示例二:子类有定义构造方法,父类没有定义构造方法
父类:

public class Person{
    
    
    public String name;
   
   // public Person(){
    
    
	//	super();
   // }
    public Number getScore(){
    
    
        return 0;
    }
    
    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }
}

子类:

public class Doctor extends Person{
    
    
    private String professional;
 
    public Doctor(){
    
    
        super();
    }
    public Doctor(String name){
    
    
    	super();
    	this.name = name;
    }

    public String getProfessional() {
    
    
        return professional;
    }
    
    public void setProfessional(String professional) {
    
    
        this.professional = professional;
    }

    public void cure(){
    
    
        System.out.println("治病");
    }

}

示例三:子类和父类中都有定义构造方法
父类:

public class Person{
    
    
    public String name;
    
    public Person(String name,String sex){
    
    
        this.name = name;
        this.sex = sex;
    }
    
    public Number getScore(){
    
    
        return 0;
    }


    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }
}

子类:

public class Doctor extends Person{
    
    
    private String professional;
    
    public Doctor(String name,String sex){
    
    
        super(name,sex);
        //如果父类中定义了带参构造,并且没有定义无参构造,
        //那么必须在子类的带参构造方法中显示的调用父类的带参构造
    }

    public String getProfessional() {
    
    
        return professional;
    }
    
    public void setProfessional(String professional) {
    
    
        this.professional = professional;
    }

    public void cure(){
    
    
        System.out.println("治病");
    }
}

使用super调用父类的构造方法时,必须为这个构造方法的第一条语句

public class Doctor extends Person{
    
    
    private String professional;
    
    public Doctor(String name,String sex){
    
    
    //报错,不是第一条语句
    	System.out.println("abc);
        super(name,sex);
    }
}

如果你的方法重写了父类的方法之一,则可以通过使用关键字super来调用父类中被重写的方法。
你也可以使用super来引用隐藏字段(尽管不建议使用隐藏字段

隐藏字段:
父类:

public class Person{
    
    
    protected String name;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }
}

子类:

public class Doctor extends Person{
    
    
    private String name;
    public Doctor(String name){
    
    
        this.name = name;
    }
}
public class PersonTest{
    
    
    public static void main(String[] args) {
    
    
        Doctor d = new Doctor("Mis");
        System.out.println(d.getName());
        //null
    }
}

如果想得到对应的name,可以重写方法

子类:

public class Doctor extends Person{
    
    
    private String name;
    public Doctor(String name){
    
    
        this.name = name;
    }

    @Override
    public String getName() {
    
    
        return name;
    }
}

如果既想得到父类的变量,又想得到子类的变量呢?
子类:

public class Doctor extends Person{
    
    
    private String name;
    public Doctor(String name){
    
    
        this.name = name;
    }
    public void show(){
    
    
        System.out.println(this.name);//访问本类中定义的name变量
        System.out.println(super.name);//访问父类中定义的变量
    }
}

如果子类和父类中没有相同的成员变量,此时使用this和super均可以调用父类的成员变量
测试:

public class PersonTest{
    
    
    public static void main(String[] args) {
    
    
        Doctor d = new Doctor("Mis");
        System.out.println(d.getName());
        d.show();
    }
}

万物皆对象

除了没有父类的Object之外,每个类都有一个且只有一个直接父类(单继承)。在没有其他任何显式超类的情况下,每个类都隐式为Object的子类。

类可以派生自另一个类,另一个类又可以派生自另一个类,依次类推,并最终派生自最顶层的类Object。据说这样的类是继承链中所有类的后代,并延伸至Object。

所有类都是Object的子类,因此,创建对象时都需要调用Object类中的无参构造方法,而Object本身就表示对象,因此创建出来的都是对象

final修饰符

应用范围:
final修饰符应该使用在类,变量以及方法上

final修饰类:

你可以将类的某些或者所有方法声明为final。在方法声明中使用final关键字表示该方法不能被子类覆盖。
object类就是这样做的----它的许多方法都是最终的

如果一个类被final修饰,表示这个类就是最终的,因此这个类不能够被继承,因为继承就是对类进行拓展

public final class Person{
    
    
    public void show(){
    
    
        System.out.println("这里是最终类里的方法");
    }
}

子类直接报错

public class Doctor extends Person{
    
    

}

final修饰方法

注: 你也可以声明整个类的final,声明为final的类不能被子类化(继承)。
例如:当创建不可变类(如String类)时,这特别有用

public class Person{
    
    
    public final void show(){
    
    
        System.out.println("这是一个最终方法,不能被重写");
    }
}

直接报错

public class Doctor extends Person{
    
    
    public void show(){
    
    

    }
}

final修饰变量

final修饰变量的时候,变量必须在对象构建时完成初始化。
final修饰的变量称为常量

public class Doctor extends Person{
    
    
    private final int number;
    public Doctor(){
    
    
        this.number = 10;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_72138633/article/details/131778687