JAVA SE 基础篇 L5-L6

it2025-06-24  3

文章目录

L51 this(1) this的作用(2) this() 2 final(1) final的作用 3 static(1) 类实例空间(2) 类加载过程和类实例化过程(3) 静态存储分配模式(4) 静态方法不能引用非静态成员/方法(5) 静态方法中不允许出现 this L61 继承(1) 工具的抽象与分层--继承(2) 继承及继承的控制 2 权限修饰符(1) public,private,protected,无修饰 3 继承关系中的构造方法(1) 构造方法的继承(2) 构造方法的执行顺序 4 super()(1) super()的含义及使用要求

L5

1 this

(1) this的作用

使用eclipse自动补全set和get方法时,会出现一个this关键字 在了解this的作用前先回顾一段C程序

int main() { int k = 10; for(int i = 0; i <= 5; i++) { int k = 5; ... } }

上述C代码中出现了两次k的定义,一个作为全局变量,一个作为局部变量,在for循环中的k从属于for循环,在for循环中的k不会影响到局部变量的值,这个道理对于java也同样成立

public void setRow(int row) { //this.row = row; row = row; }

在这个set方法中如果去掉this.那么=左边的row实质上还是形参变量row,这是一个没有意义的赋值方式,并没有真正的完成set方法,为了告诉java编译器=左侧的row其实应该是对象的成员row,所以必须用this加以区分

this的作用: 1,区分局部变量和成员变量 2,指代对象本身

方法必须通过对象调用,对象.方法()是调用的基本形式

所调用的方法中,如果存在this,那么这个this就代表:调用这个方法的调用者–使用该方法的对象,对象的本质是指向实例成员的指针,使用this.方法()时,this的本质就是对象,就是指针

(2) this()

当出现this()时JVM将其当作方法看待,这个方法固定表示构造方法

第9行是对单参构造方法的调用,12行是对双参构造方法的调用

this()的使用方式: 1,参数个数决定其调用的具体方法,是无参还是带参 2,this()只能在构造方法中出现 3,构造方法中若出现this(),则必须位于第一条语句 4,this()的使用要注意避免递归,如无参构造方法中不能使用this(),否则会造成无限递归,使程序错误

2 final

(1) final的作用

在C中存在着宏替换的概念,使用宏替换的手段可以避免代码中出现的神仙数字和提高代码的可维护性,所谓神仙数字就是指代码的作者第一次编写时自己写的一些用来逻辑判断的数字,如果不做注释那么后来者很难明白这些数字的真实含义

java中的final关键字相当于C中的const关键字,被final修饰的变量,就是只读变量

通过final来定义只读变量,并且大量的使用这些只读变量可以极大提高程序的可读性和可维护性

final修饰的常量在类实例化时完成初始化

3 static

(1) 类实例空间

当需要用new新建一个对象时,new的核心功能是申请类实例空间,类有两种成员:数据成员和方法成员,那么类的每一个实例空间是否都有各自完备的数据成员和方法成员呢?

回答这个问题先回顾C中,C中多次强调内存是计算机系统非常宝贵的资源,因此在编程中要珍惜和高效率的使用内存,在JVM中也是如此,有一份就够用

JVM对类的成员和方法是区别对待的,首先像结构体实例一样,每一个结构体实例应该有各自独立的成员,因此类实例有着独属于自己的独立数据成员,这样才能对不同实例的各自的数据成员进行互不干扰的访问

但方法的本质是指令,指令即代码一旦编译完毕无法进行更改,所以方法有一份就够由类创建的所有成员使用,每一个类实例空间拥有自己的,独立的成员变量,但所有本类实例空间共享一份方法

(2) 类加载过程和类实例化过程

在JVM中导入一个类时,这个过程称为类加载过程,即出现类名时,JVM需要将出现的类加载到内存中

当需要新建一个对象时,使用new时由类创建的实例空间这个过程称为类实例化过程

(3) 静态存储分配模式

static继承了C中static的精髓,与C中static一样java中用static修饰的成员,其空间的申请操作远早于非static修饰的成员

static修饰的成员称为静态成员,static修饰的方法称静态方法 JVM对类加载时就申请了静态成员的空间,也就是说在一个类还没有任何实例化的对象(即new对象)时,静态成员就已经存在了,在没有任何类的对象前都可以使用静态成员

上述的pointCount是静态成员,increasePointCount()和getPointCount()是静态方法,可以看到它们之前并没有由对象引用,之间也并未new过对象,引用它们的是类名称TestL5

类名称.静态成员,这就是静态成员在类外的引用方法

方法必须通过对象来调用,但静态方法可以直接通过类名来调用,从对静态成员和静态方法的调用语法来看,静态成员是类的公有财产,不是一个类new出来的对象的私有财产

(4) 静态方法不能引用非静态成员/方法

类的静态方法可以在没有实例化该类的任何对象的前提下调用,但类的非静态成员,必须通过new才能得到内存空间,也必须通过对象才能引用这个非静态成员

理解上述话语先回到类加载和类实例化过程,类加载过程中所有的静态成员和静态方法都已经产生了,但此时还没有非静态成员和非静态方法,只有类实例化过程后才有非静态成员和非静态方法,我们可以在类加载过程后直接通过类名.静态成员/方法()来调用它们,但是在类实例化过程前我们不能用静态方法去调用一个 “还不存在的成员/方法”

类的方法中可以直接引用类的成员,类的方法中直接对非静态成员的引用事实上都存在了一个实例化的对象,类方法中出现的 “没有前缀的非静态成员,都可以增加一个this.” 上述类中方法可以直接引用本类中的成员和方法

(5) 静态方法中不允许出现 this

public static void printPoint(Point point) { //System.out.println(row +" "+ col); //System.out.println(this.row +" "+ col); System.out.println(point.row +" "+point.col); }

上述例子打开第2,3行的注释程序会报错,printPount确实是一个静态方法它不允许引用非静态成员和非静态方法,因为可能存在引用的成员和方法所属的对象还没有被实例化,从而可能引用一个不存在的值,java会禁止这样的做法,但第4行的程序却是正确的,因为row和col这两个非静态成员通过对象point传来,point已经明确被实例化了,自然可以引用

java明确禁止了静态方法引用非静态成员和非静态方法,因为可能引用不存在的对象,那么是不是可以考虑在引用静态方法前,先实例化一个对象,那么不就可以在静态方法中引用这个对象的非静态成员和非静态方法?

对上述的说法,虽然理论上是正确的,但是实际中却绝对不可行,如果想要这样使用,必须要求参与开发的每个java程序员都自觉地先实例化对象在引用,这明显是不现实地,这与java“化繁为简,尽量避免错误”背道而驰

L6

1 继承

(1) 工具的抽象与分层–继承

面向对象的程序设计扩展了基于对象的程序设计,可以提供类型/子类型的实现,这通过一种称为继承的机制而获得。java通过一种派生类的机制来支持继承,被继承的类称为父类,新的类称为子类,一般把父类和子类实例的集合称作类继承层次结构

类的继承关系:Son属于Father 面向对象程序设计更强调“贴近认类思维习惯和模式” 如学生->大学生->本科生,它们之间存在着从属关系,大学生具有本科生的所有属性和方法,本科生类可以从大学生类中继承这些成员和方法,而不必重新编码,这就是代码复用的直接体现,同时也是继承机制的目的之一

子类自动拥有父类部分或全部的属性和方法,同时可以继续定义子类自己的属性和方法,使得子类信息更详细,功能更明确

对于上述语句的“部分或全部”,这说明继承是可以控制的

(2) 继承及继承的控制

新建一个类,选择它的父类为GrandPa,会自动出现extends关键字,当使用this.时会发现可以使用很多GrandPa类中的成员和方法

详细观察this.后面自动补全的方法,可以看到缺少了private修饰的成员和方法,这就是利用权限修饰符对继承的控制,类的继承不但区分私有公有,还区分包内包外,都是由权限修饰符public,private,protected,无修饰符控制的

2 权限修饰符

(1) public,private,protected,无修饰

public和private是两个极端,从保护功能来讲,public最弱,private最强

protected修饰的成员和方法,无论是否在同一个包下,子类都可以继承,且同一包下的类,可以通过其对象引用

无修饰的成员和方法,在同一包下的子类可以继承,不再同一包下的子类不能继承,且不在同一包下的其它派生类不能引用

使用技巧: 1,凡是打算为子类继承的成员和方法,用protected修饰 2,不打算被包外的类引用的成员和方法,不用写任何修饰符

3 继承关系中的构造方法

(1) 构造方法的继承

继承的目的之一是为了代码复用,层层的继承结构保证子类有丰富的父类成员和方法,子类new出来的对象可以使用其上的父类允许它使用的成员和方法,但这个过程中每个父类中都需要构造方法来初始化诸成员的值,这个构造方法可以不写(使用默认的无参构造),也可以自定义单参,双参,多参等

创建三个具有继承关系的简单类:

GrandPa.java package com.mec.Extends.core; public class GrandPa { public GrandPa() { System.out.println("执行grandpa构造方法"); } } Parent.java package com.mec.Extends.core; public class Parent extends GrandPa { public Parent() { System.out.println("执行parent构造方法"); } } Child.java package com.mec.Extends.core; public class Child extends Parent { public Child() { System.out.println("执行child构造方法"); } }

Test.java中对Child类实例化:

(2) 构造方法的执行顺序

在Test类的主函数中,虽然只有一条实例化Child类的语句,但执行结果却发现,构造方法是从基类的构造方法开始执行的,且是自动执行的

事实上,JVM对于有继承关系的类的构造方法先从当前类开始,根据继承关系,追溯到最开始的祖先类,然后再沿着继承关系向下,逐个执行构造方法

如果没有定义无参构造方法,则JVM在实例化类对象时会自动地执行一个默认的无参构造方法,但在继承中构造方法的继承可能会出现如下的问题:

GrandPa.java package com.mec.Extends.core; public class GrandPa { private int one; private int two; public GrandPa(int one, int two) { this.one = one; this.two = two; System.out.println("执行grandpa构造方法"); } } Parent.java package com.mec.Extends.core; public class Parent extends GrandPa { public Parent() { System.out.println("执行parent构造方法"); } }

将GrandPa类中无参构造改成了双参构造,更改后,原来的Parent类出现了问题

无论子类执行的构造方法是无参的还是多参的,在默认情况下,JVM只调用基类的无参构造方法

由于GrandPa类没有无参构造方法,它的子类Parent类必须要执行父类的构造方法,什么都不写是默认使用无参构造,但GrandPa类没有无参构造方法自然会出错,所以这里必须明确地使用父类的双参构造方法

4 super()

(1) super()的含义及使用要求

this(0,0)代表调用本类的双参构造方法,则super(0,0)即为调用基类的双惨构造方法,super class就是基类,父类的意思

无论子类执行的构造方法是无参的还是多参的,在默认情况下,JVM只调用基类的无参构造方法

用super()指明了使用父类的具体的哪一个构造方法,就脱离了“默认情况”

super()的使用要求: 1,只能出现在构造方法中 2,如果有super(),那么它必须是构造方法的第一条语句

最新回复(0)