JAVA基础回顾

1、方法重载

在实际开发过程中,会遇到一个问题:方法的功能实现上及其类似,但却有一些不同,如果每个功能实现都要重新编写一个方法,过于繁琐,也不好想方法名,例子如下所示,相当繁琐

JAVA基础回顾_第1张图片

引入方法重载

1.1什么是重载?

在同一个类中,方法名相同,参数不同的方法。与返回值无关。

参数不同:个数不同、类型不同、顺序不同(符合其一则是重载)

JAVA基础回顾_第2张图片

如果参数相同,则不构成重载关系

JAVA基础回顾_第3张图片

如不在同一个类中,则不构成重载关系

JAVA基础回顾_第4张图片

2.基本数据类型和引用数据类型

2.1 基本数据类型和引用数据类型有哪些?

JAVA基础回顾_第5张图片

2.2 基本数据类型

基本类型变量中存储的是真实的数据,数值存储在自己的空间里

即便是赋值给其他变量,也是赋的真实的值

JAVA基础回顾_第6张图片

2.3 引用数据类型

引用数据类型中记录的是堆内存的地址值,而不是真实的数据,真实的数据在堆内存new的对象中

数据值是存储在堆空间里,在自己空间里存储的是地址值

赋给其他变量时,赋的是地址值

JAVA基础回顾_第7张图片

2.4 方法传递基本数据类型的内存原理

示例如下

对于基本数据类型,局限于方法的作用域,调用方法并不影响方法外部的基本数据类型的变量。

传递基本数据类型时,传递的是真实的数据,形参的改变,不影响实际参数的值

JAVA基础回顾_第8张图片

2.5 方法传递引用数据类型的内存原理

此时传递给方法的并不是变量真实的数据,而是堆空间的地址值,因此,方法会直接去堆空间对真实值进行修改,方法执行后数据改变

JAVA基础回顾_第9张图片

3、类对象

3.1 private关键字

  1. 是一个权限修饰符号

  1. 可以修饰成员变量

  1. 被private修饰的成员变量只有在本类中才能访问

JAVA基础回顾_第10张图片

所以,在对象的实例中(也就是箭头指向的部分),不再使用图中简单的 person.age 来进行对象属性的设定和提取,而是 改成了person.setAge() 来设定 / person.getAge() 来提取。这样可以对属性的 age 有更加精细化的规定和设计,而不再局限于 int 属性所规定的范围。

3.2 this关键字

当执行set方法的时候,set内参数名称与成员变量一致的时候,容易发生混淆,导致方法无法正确执行

JAVA基础回顾_第11张图片

局部变量定义在方法内部,而成员变量定义在方法外部,类中,在执行set方法时,同名情况下容易发生混淆。如图,最后在控制台输出的age是定义的局部变量age,因为程序执行是遵循就近原则的,所以直接输出局部变量。

JAVA基础回顾_第12张图片

此时需要加入this方法,用this指代的变量为成员变量,不用this指代的依旧遵循就近原则。

3.3、构造方法

3.3.1 构造方法的格式

JAVA基础回顾_第13张图片

特点:1、方法名与类名相同,大小写也要一致

2、没有返回值类型

3、没有具体的返回值

4、构造方法不可以被static final等修饰符修饰,可以被public 等权限修饰符修饰

执行时机:1、创建对象时由虚拟机调用,不可手动调用构造方法;

2、每创建一次对象,就会调用一次构造方法

如果我们没有写任何的构造方法,那么虚拟机会给我们加一个空参构造1方法

JAVA基础回顾_第14张图片

3.3.2 构造方法的注意事项

JAVA基础回顾_第15张图片

3.4 标准的JAVABEAN类

JAVA基础回顾_第16张图片

3.5 对象内存图

3.5.1 单对象内存图

  1. 加载class文件

  1. 申明局部变量

  1. 在堆内存中开辟一个空间

  1. 默认初始化

  1. 显示初始化

  1. 构造方法初始化

  1. 将堆内存中的地址值赋给左边的局部变量

其中4、5、6三步都是对第三步在堆内创建的对象进行赋值

示例讲解

  1. 加载class文件

将TestStudent这个类的class文件加载到方法区内部,将main方法进行自动存储并执行

JAVA基础回顾_第17张图片
  1. 申明局部变量

main方法进入栈内存中,开始执行,而方法区中也会对应的载入Student的class文件

JAVA基础回顾_第18张图片

随后,在main方法中开辟出一个空间,存储局部变量s,用于存储地址值

  1. 在堆内开辟空间

随着new 关键字的执行,堆内开辟出空间,并在堆内存中存放了成员方法在方法区的地址值

JAVA基础回顾_第19张图片
  1. 默认初始化

给类对象的成员变量赋予默认的值,如name默认值为null,age的默认值为0

JAVA基础回顾_第20张图片
  1. 显式初始化

如在类中已赋予了一定的值,在显示初始化的过程中,会将这些值赋予上去

JAVA基础回顾_第21张图片
  1. 构造方法初始化

即执行构造方法,如无构造方法则默认执行无参构造

  1. 将堆内存的地址赋值给左边的局部变量

JAVA基础回顾_第22张图片

3.5.2 多对象内存图

重点便是class字节码文件无需重复加载

JAVA基础回顾_第23张图片

3.5.3 当引用了已有的对象时

两个变量引用了同一个地址值,即两个变量都能对在堆内存的对象进行操作

JAVA基础回顾_第24张图片

可以断开局部变量对堆内存对象的操作,即把地址值改写,如此便无法找到对象,报空指针异常

JAVA基础回顾_第25张图片

3.6 this的内存原理

this的本质:所在方法调用者(堆内存中的某对象)的地址值

this的作用:用于区分方法中的局部变量和成员变量

JAVA基础回顾_第26张图片

3.7 成员变量和局部变量

成员变量和局部变量的区别

JAVA基础回顾_第27张图片

4、String类内存分析

创建字符串对象有多种方式

4.1直接赋值方式

JDK7之前,StringTable是放在方法区中的,JDK7之后,StringTable放在堆内存中

采用直接赋值的方式

示例:

首先执行main方法,对于s1变量,判断串池中是否已经含有这个字符串("abc"),如果没有,则在串池中进行创建,再将串池中创建的地址值传入栈内存中的局部变量。

JAVA基础回顾_第28张图片

对于s2变量,此时串池中已有"abc",则不会创建新的字符串,而是会复用串池中已有的字符串对象的地址

JAVA基础回顾_第29张图片

4.2 采用new String的方法进行赋值

此时并不是在串池中创建了,此时是在堆内存开辟新的空间,就像新创建了一个对象一样,将地址值赋给局部变量。局部变量并不会复用地址,因此当字符串相同的多了,相对于直接赋值,会浪费更多的内存空间。

JAVA基础回顾_第30张图片

4.3 字符串拼接的内存原理

4.3.1 直接拼接字符串

示例所示

JAVA基础回顾_第31张图片

拼接的时候没有变量,都是字符串。触发字符串的优化机制。在编译的时候已经是最终的结果了。

JAVA基础回顾_第32张图片

4.3.2 采用变量进行拼接

JDK8之前

会使用StringBuilder的append方法进行拼接

拼接过程中,会创建一个StringBuilder对象,使用append方法拼接,示例如下所示

在拼接s2时,创建StringBuilder,使用append进行拼接,即两两拼接一下,就需要创建一个StringBuilder对象,非常麻烦,对此JDK8进行了优化

JAVA基础回顾_第33张图片

在拼接s3时,又创建了StringBuilder对象,进行了拼接,如此反复创建StringBuilder,非常耗费资源。

JDK8变量拼接的原理

JDK8对于变量的拼接,做了优化,会先预估拼接的次数,将需要拼接的字符串存放到数组里,从而做到只创建一次StringBuilder,便实现所有变量的拼接。

当然预估也是需要耗费时间和资源的,对于频繁拼接字符串,还是耗时耗力的

JAVA基础回顾_第34张图片

4.3.3 采用StringBuilder对字符串进行拼接

无需重复创建StringBuilder对象,可以直接进行拼接

JAVA基础回顾_第35张图片

4.4 String小结

4.4.1字符串拼接底层原理:

4.4.2 StringBuilder提高效率原理:

即不用重复创建StringBuilder对象

4.4.3 StringBuilder 扩容机制

默认创建一个长度为16的字节数组

添加的内容长度小于16,直接存

当超出容量时,会按当前容量*2+2的机制进行扩容,容量最长是Integer.MAX_VALUE,如果扩容之后还不够,以实际长度为准

5、Static 静态变量

采用static关键字,对类中的属性赋值后,所有创建的类实例对象都共享这个值。

JAVA基础回顾_第36张图片
JAVA基础回顾_第37张图片
JAVA基础回顾_第38张图片

5.1 静态变量

被static修饰的成员变量,叫做静态变量

特点:1、被该类所有对象共享

2、不属于对象,属于类

3、随着类加载而加载,优先于对象存在

调用方式:

1、类名调用(推荐)

2、对象名调用

5.2 静态方法

被static修饰的成员方法,叫做静态方法

特点:多用于测试类和工具类中

JavaBean类中很少使用

调用方式:

  1. 类名调用

  1. 对象名调用

5.3 静态变量内存图

可以见得,静态变量是随着类的加载而加载的,优先于对象出现的

堆内存有专门的位置存储静态变量,叫静态区

JAVA基础回顾_第39张图片

在new 完对象,并执行方法时,执行过程如图所示

JAVA基础回顾_第40张图片
JAVA基础回顾_第41张图片

5.4 static注意事项

  1. 静态方法只能访问静态变量和静态方法

  1. 非静态方法可以访问静态变量或者静态方法,也可以访问非静态的成员变量和非静态的成员方法

  1. 静态方法中是没有this关键字的(静态变量是共享的,并不针对某一个对象)

无论是非静态方法,非静态成员变量,或者是this,针对的都是某一个对象属性的修改,但是静态方法是针对于类的,对于该类创建的对象,是共享的,并不能在静态方法内部区去处理它。

JAVA基础回顾_第42张图片
JAVA基础回顾_第43张图片

从内存角度解析 为什么静态方法不能调用非静态成员变量

可知执行method时,并不能输出name,因为静态区根本没有name,静态方法执行时,变量是需要到静态区中获取的。所以静态方法并不能调用实例对象变量

JAVA基础回顾_第44张图片

5.5 重新认识main方法

JAVA基础回顾_第45张图片
JAVA基础回顾_第46张图片

6、继承

6.1 继承的概念

当类与类之间,存在相同(共性)的内容,并满足子类是父类的一种,就可以考虑使用继承,来优化代码

JAVA基础回顾_第47张图片
JAVA基础回顾_第48张图片

6.2 继承的特点

JAVA只支持单继承(一个子类只能继承一个父类),不支持多继承(子类不能同时继承多个父类),但支持多层继承(子类A继承父类B,父类 B可以继承父类C)

Object是所有类的默认父类

  1. JAVA只能单继承,不能多继承,但可以多层继承

  1. JAVA所有的类都直接或间接的继承于Object

  1. 子类只能访问父类中非私有的成员

  1. 独立完成继承体系的案例

6.3 子类到底能继承父类的哪些内容

6.3.1对于父类的构造方法,无论是私有还是非私有都不可继承

子类继承过来父类的构造方法,会导致构造方法名称和类名不一致的情况

JAVA基础回顾_第49张图片

6.3.2对于父类的成员变量,私有和非私有的都能继承,不过子类无法调用父类的非私有的成员变量

对父类非私有的成员变量:

内存流图

方法区会加载子类和父类的class文件

等执行到new关键字时,在堆中开辟内存,此内存中分为两块,一块是父类的成员变量,另一块是子类的成员变量

JAVA基础回顾_第50张图片

对父类私有的成员变量

无法直接调用父类的私有成员变量

JAVA基础回顾_第51张图片

6.3.3对于父类的成员方法,子类能继承父类的非私有成员方法,但是不能继承父类私有的成员方法

对于父类的非私有、非静态、非final的方法,父类会建立一张虚方法表,子类在继承后,也会继承父类的虚方法表,并且在父类的基础上,添加自己的虚方法

只有父类中的虚方法才能被子类继承

JAVA基础回顾_第52张图片

内存流图

对于下图的子类和父类,方法区加载class文件如下

JAVA基础回顾_第53张图片

其中Object虚方法表中有5个方法,Fu.class文件,虚方法表中包括这5个方法及其非私有方法fuShow1(),而Zi类继承FU类,其虚方法表中加入了ZiShow方法。

JAVA基础回顾_第54张图片

fushow2 不在虚方法表中,子类无法调用

JAVA基础回顾_第55张图片

6.4 成员变量的访问特点

在方法中,对于重名的变量,还是使用就近原则

JAVA基础回顾_第56张图片

如果想访问本类的成员变量,采用this关键字,会从子类开始找,如果子类没有,会往父类中去找

如果想要访问父类的成员变量,采用super关键字,会从父类中开始找,如果在父类中找不到,会继续回溯到父类的父类中去找

JAVA基础回顾_第57张图片

6.5 成员方法的访问特点

6.5.1 this super关键字

在继承关系中,this调用子类的方法,如果子类没有该方法,会自动往其父类上追踪

super调用父类的方法,如果父类没有该方法,会往父类的父类上去找

this 理解为一个变量,表示当前方法调用者的地址值

super 代表父类存储空间

JAVA基础回顾_第58张图片

6.5.2 子类对父类的方法进行重写

对父类方法进行重写,对于子类会覆盖掉父类的方法(即子类虚方法表的方法发生改变)

重写注意事项:

  1. 重写方法的名称、形参列表必须与父类中的一致

  1. 子类重写父类方法时,访问权限子类必须大于等于父类

  1. 子类重写父类方法时,返回值类型子类必须小于等于父类

  1. 私有方法不能被重写、静态方法不能被重写,重写的只能是虚方法表内的方法

JAVA基础回顾_第59张图片

6.6 构造方法的访问特点

  1. 子类不能继承父类的构造方法,但是可以通过父类调用

  1. 子类构造方法的第一行,有一个默认的super();

  1. 默认先访问父类中无参的构造方法,再执行自己

  1. 如果想要调用父类的有参构造,必须手动书写

JAVA基础回顾_第60张图片

在子类中调用父类的构造方法

JAVA基础回顾_第61张图片

7 多态

什么是多态:即同类型的对象,表现出不同的形态

多态的表现形式:父类类型 对象名称=new 子类对象()/接口 对象名称=new 实现类名称()

其中新建出的实例对象,只能调用子类重写过父类的方法,父类中未定义的方法,子类中定义过的无法调用

可以由下图显而易见

JAVA基础回顾_第62张图片

7.1 多态的应用场景

比如需要注册账号,分为学生、老师、管理员三种类型,如果不使用多态,则要重复写三种注册方法,去接收三个不一样的类。

有了多态就好多了,用一个他们共同的父类去被他们继承,可以集成他们的共有属性,在父类中写一个方法,其他的子类根据具体的需要去重写该方法即可

实现具体例子如下:

一个方法可以接收多类对象,这就是多态的优越性

JAVA基础回顾_第63张图片

7.2 多态调用成员的特点

  1. 变量调用:编译看左边,运行也看左边

在编译过程中,编译器会看左边的父类有没有该成员变量,如果有,编译成功,没有则失败

JAVA基础回顾_第64张图片

  1. 方法调用:编译看左边、运行看右边

即会看左边父类中有没有这个方法,如果有则编译成功;实际执行会调用子类的虚方法表中的方法

用内存图来解释多态的调用特点

JAVA基础回顾_第65张图片

7.3 多态的优势和弊端

优势如上所示,会比较方便,不用重复建方法来接收不同的类,用多态后,可用一个方法接收所有的子类和父类

弊端:不能使用子类的特有功能,如果需要使用,需要强转类,如转换类型与真实对象类型不一致会报错

8、final关键字

final修饰方法:表明该方法是最终方法,不能被重写

final修饰类:表明该类是最终类,不能被继承

final修饰变量:叫做常量,只能被赋值一次

JAVA基础回顾_第66张图片

9、权限修饰符

权限修饰符:是用来控制一个成员能够被访问的范围的

可以修饰成员变量、方法、构造方法、内部类

浅显的来说 A a=new A(),对他的属性b赋值

在private修饰b的时候,a.b=10这样的赋值方式,或者直接访问a.b,只有在同一个类才做得到

默认情况下,在同一个包下的类都能访问到

protected权限下,不同包下的子类也可以访问到

public权限下,整个项目工程的类都可以直接访问

JAVA基础回顾_第67张图片

10、抽象类和抽象方法

抽象方法:将共性的行为(方法)抽取到父类之后,由于每一个子类执行的内容是不一样的,所以,在父类中不能确定具体的方法体,该方法就可以定义为抽象方法

抽象方法必须重写

抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类

注意事项:抽象类不能实例化

抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类

可以有构造方法

抽象类的子类要么重写抽象类中的所有抽象方法,要么是抽象类

11、接口

JAVA基础回顾_第68张图片
JAVA基础回顾_第69张图片
JAVA基础回顾_第70张图片

你可能感兴趣的:(jvm)