欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaSE-04Java类的高级特性

程序员文章站 2024-03-08 15:07:10
...

 

Table of Contents

 

Java类的高级特性

1:封装

2:继承

2.1:继承

2.2:extends 关键字

2.3:父子类初始化顺序:

2.3:单继承性

2.4:super

3:多态

3.1:什么是多态?

3.2:多态与类型

1:引用多态

3.3:执行那个方法

3.4:instanceof 运算符

4:静态(static)

4.1:static静态修饰符

4.2:static的内存分配

4.3  static 的基本规则

4.4:静态初始快;

5:方法的覆盖和重载

5.1:方法的覆盖

5.1.1:什么是方法的覆盖

5.1.2:方法覆盖的规则

5.2:方法的重载

5.2.1:什么是重载

5.2.3:重载的规则

5.3:覆盖和重载的比较

6:final(最终的)

7:谈Java内存分配

7.1:方法区

7.2:栈内存

7.3:堆内存

7.4:String的内存分配


Java类的高级特性

1:封装

封装是 JAVA 面向对象的特点的表现,封装是一种信息隐蔽技术。它有两个含义:即把对象的全部属性和全部服务结合在一起,形成一个不可分割的独立单位;以及尽可能隐藏对象的内部结构。也就是说,如果我们使用了封装技术的话,别人就只能用我们做出来的东西而看不见我们做的这个东西的内部结构了。

封装的功能:

1:迫使用户去使用一个界面访问数据

2:使代码更好的维护

3:隐藏对象的使用细节

示例:也就是get和set方法,并且类属性都是private修饰的

package com.wkl.springboot.bean;

/**
 * Description:
 * Date:       2020/6/4 - 下午 2:46
 * author:     wangkanglu
 * version:    V1.0
 */
public class Department {
    private Integer id;
    private String departmentName;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getDepartmentName() {
        return departmentName;
    }

    public void setDepartmentName(String departmentName) {
        this.departmentName = departmentName;
    }
}

 

2:继承

2.1:继承

“继承”是面向对象软件技术当中的一个概念。如果一个对象 A 继承自另一个对象 B,就把这个 A 称为“B 的子对象”,而把 B 称为“A 的父对象”。继承可以使得子对象具有父对象的各种属性和方法,而不需要再次编写相同的代码。在令子对象继承父对象的同时,可以重新定义某些属性,并重写某些方法,即覆盖父对象的原有属性和方法,使其获得与父对象不同的功能。

总结也就是子类拥有父类的所有属性和方法

2.2:extends 关键字

在 Java 中使用 extends 关键字来表达继承的关系,

如:

public class Employee {
    String name;
    Date hireDate;
    Date dateOfBirth;
    String jobTitle;
    int grade;
    ...
}
public class Manager extends Employee {
    String department;
    Employee[] subordinates;
    ...
}

2.3:父子类初始化顺序:

1:Java 技术安全模式要求在子类执行任何东西之前,描述父类的一个对象的各个方面都必须初始化。因此,Java 编程语言总是在执行子构造方法前调用父类构造方法的版本。有继承的类在运行的时候,一定要记得: 初始化子类必先初始化父类,这是 Java 程序的一个基本运行过程。

2:子类的构造方法必须调用父类的构造方法

3:如果子类的构造方法没有显示调用父类的构造方法,则系统默认调用父类的无参构造方法

4:如果子类构造方法,显示的调用了父类的构造方法,那么必须在子类的构造方法的第一行;

5:如果子类的构造方法即没有显示调用父类的构造方法,而且父类有没有无参构造方法,那么编译出错

6:子类调用父类的有参构造方法需要加super(参数)

 

JavaSE-04Java类的高级特性

2.3:单继承性

单继承性:当一个类从一个唯一的类继承时,被称做单继承性。单继承性使代码更可靠。接口提供多继承性的好处,而且没有(多继承的)缺点。

2.4:super

关键字 super 可被用来引用该类的父类,它被用来引用父类的成员变量或方法。父类行为被调用,就好象该行为是本类的行为一样,而且调用行为不必发生在父类中,它能自动向上层类追溯

super 关键字的功能:
点取父类中被子类隐藏了的数据成员。
点取已经覆盖了的方法。
作为方法名表示父类构造方法。

调用父类的构造方法:

1:子类的构造方法必须调用父类的构造方法

2:如果子类的构造方法没有显示调用父类的构造方法,则系统默认调用父类的无参构造方法

3:如果子类构造方法,显示的调用了父类的构造方法,那么必须在子类的构造方法的第一行;

4:如果子类的构造方法即没有显示调用父类的构造方法,而且父类有没有无参构造方法,那么编译出错

5:子类调用父类的有参构造方法需要加super(参数)

3:多态

3.1:什么是多态?

多态是同一个行为具有多个不同表现形式或形态的能力。

方法没有多态的说法,严格说多态是类的特性。但是也有对方法说多态的,了解一下,比如前面学到的方法 覆盖称为动态多态,是一个运行时问题; 方法重载称为静态多态, 是一个编译时问题。

3.2:多态与类型

1:引用多态

              父类的引用指向本类的对象

              父类的引用指向子类的对象

3.3:执行那个方法

这里会给我们带来一个麻烦,父子类中有相同的方法,那么在运行时到底调用哪一个方法呢?

一句话概括,new 谁就是用谁的方法;

3.4:instanceof 运算符

多态性带来了一个问题 :如何判断一个变量所实际引用的对象的类型,那就是是用instanceof 运算符;

instanceof 运算符功能:用来判断某个实例变量是否属于某种类的类型。

boolean b   = a instanceof B;   //判断a对象的类型是否为B类

4:静态(static)

4.1:static静态修饰符

static 修饰符能够与 属性、方法和内部类一起使用,表示是“静态”的。类中的静态变量和静态方法能够与“类名”一起使用,不需要创建一个类的对象来

类中的静态变量和静态方法能够与“类名”一起使用,不需要创建一个类的对象来访问该类的静态成员。所以 static 修饰的变量又称作“类变量”。这与实例变量不同。实例变量总是用对象来访问,因为它们的值在对象和对象之间有所不同。

4.2:static的内存分配

在上面的例子中,无需创建类的对象即可访问静态变量,之所以会产生这样的结果,是因为编译器只为整个类创建了一个静态变量的副本,因此它能够用类名进行访问。一个 static 变量只会有一个内存空间,虽然有多个类实例,但这些类实例中的这个
static 变量会共享同一个内存空间。

static 的变量是在类装载的时候就会被初始化。也就是说,只要类被装载,不管你是否使用了这个 static 变量,它都会被初始化。

4.3  static 的基本规则

在同一个类中,静态方法只能访问静态属性或方法,静态方法不能够直接调用非静态属性或方法;
如果访问控制权限允许,静态属性和静态方法可以使用类名加“.”方式调用;也可以使用实例加“.”方式调用;
静态方法中不存在当前对象,因而不能使用this,当然也不能使用super;
静态方法不能被非静态方法覆盖;
构造方法不允许声明为static的;
局部变量不能使用static修饰

4.4:静态初始快;

静态初始器(Static Initializer)是一个存在与类中方法外面的静态块。静态初始器仅仅在类装载的时候(第一次使用类的时候)执行一次。静态初始器的功能是:往往用来初始化静态的类属性。

示例:

class Count {
    public static int counter;
    static {// 只运行一次
        counter = 123;
        System.out.println("Now in static block.");
    }

初始化顺序:静态初始快 》 初始快 》构造方法

1:静态初始快只能给静态变量赋值,切执行一次

2:static变量共享一个内存,但是变量可变;

5:方法的覆盖和重载

5.1:方法的覆盖

5.1.1:什么是方法的覆盖

在类继承中,子类可以修改从父类继承来的行为,也就是说子类能创建一个与父类方法有不同功能的方法,但具有相同的:名称、返回类型、参数列表。如果在子类中定义一个方法,其方法名称、返回值类型及参数列表正好与父类中方法的名称、返回值类型及参数列表相匹配,那么称,子类的方法覆盖了父类的方法。

5.1.2:方法覆盖的规则

子类的方法的名称以及子类方法参数的顺序必须与父类中的方法的名称以及参数的顺序相同,以便该方法覆盖父类版本。下述规则适用于覆盖方法:
1:覆盖方法不能比它所覆盖的方法访问性差(即访问权限不允许缩小)。
2:覆盖方法不能比它所覆盖的方法抛出更多的异常。

 

5.2:方法的重载

5.2.1:什么是重载

在同一个 Java 类中,如果出现了方法名称相同,而参数列表不同的情况就叫做重载。

参数列表不同的情况包括:个数不同、类型不同、顺序不同等等。特别提示,仅仅参数变量名称不同是不可以的。

5.2.3:重载的规则

1:方法名称必须相同

2:参数列表必须不同(个数不同,或类型不同,或参数排列顺序不同)。
3:方法的返回类型可以相同也可以不相同。仅仅返回类型不同不足以成为方法的重载。

5.3:覆盖和重载的比较

1:重载方法: 在一个类(或父子类)中用相同的名字创建多个方法(每个方法的参数表不同)
2:方法覆盖: 在一个类中创建的方法与父类中方法的名字、返回类型和参数表相同,覆盖是
针对两个类说的,而且必须是子类(或孙类,孙孙类等)覆盖掉父类的方法

 

6:final(最终的)

在 Java 中声明类、属性和方法时,可使用关键字 final 来修饰。final 所标记的成分
具有“终态”的特征,表示“最终的”意思。

1:final修饰类,则该类不可以被继承

2:final修饰方法,则该方法不允许重写

3:final修饰属性,则该属性只可以赋值一次,而且不可以修改;

4:final修饰引用,则该引用指向的地址不可以改变

7:谈Java内存分配

7.1:方法区

方法区存放装载的类数据信息包括:
(1)基本信息:

每个类的全限定名
每个类的直接超类的全限定名(可约束类型转换)
该类是类还是接口
该类型的访问修饰符
直接超接口的全限定名的有序列表

2)每个已装载类的详细信息:

运行时常量池:存放该类型所用的一切常量(直接常量和对其它类型、字段、方法的符号引用),它们以数组形式通过索引被访问,是外部调用与类联系及类型对象化的桥梁。
它是类文件(字节码)常量池的运行时表示。
字段信息:类中声明的每一个字段的信息(名,类型,修饰符)。
方法信息:类中声明的每一个方法的信息(名,返回类型,参数类型,修饰符,方法的字节码和异常表)。
静态变量:到类 classloader 的引用:即到该类的类装载器的引用。
到类 class 的引用:虚拟机为每一个被装载的类型创建一个 class 实例,用来代表这个被装载的类。

7.2:栈内存

Java 栈内存以帧的形式存放本地方法的调用状态(包括方法调用的参数,局部变量,中间结果等)。每调用一个方法就将对应该方法的方法帧压入 Java 栈,成为当前方法帧。当调用结束(返回)时,就弹出该帧。

也就是说:在方法中定义的一些基本类型的变量和对象的引用变量都在方法的栈内存中分配。当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作它用

栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(int,short, long, byte, float, double, boolean, char)和对象句柄。 栈有一个
很重要的特殊性,就是存在栈中的数据可以共享。

7.3:堆内存

堆内存用来存放由 new 创建的对象和数组。在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。 在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。

Java 的堆是一个运行时数据区,对象从中分配空间。堆的优势是可以动态地分配内存大小,
生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java 的垃圾收集器会自动
收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。

7.4:String的内存分配

String 是一个特殊的包装类数据。可以用:
String str = new String("abc");
String str = "abc";

两种的形式来创建,第一种是用 new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。而第二种是先在栈中创建一个对 String 类的对象引用变量 str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令 str 指向"abc",如果已经有"abc" 则直接令 str 指向"abc"。

String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true

他的内存图是:他存放在栈中

JavaSE-04Java类的高级特性

String str1 = new String ("abc");
String str2 = new String ("abc");
System.out.println(str1==str2); // false

他的内存图是:他在堆中重新new一个对象

JavaSE-04Java类的高级特性

String s1 = null;

String s2 = "";

s1只是在栈内存中分配一个s1,没有分配堆内存

s2在堆内存中分配了一个内存;只不过内存中没有数值