java入门(起始于string截至到内部类)

api就是java中已经写好的各种类,直接拿来用就行

一.字符串

1.string类

(1)string类的特点

(2)string类对象的创建方法(主要用“直接赋值方法”,最后两种也常用)

(3)字符串的内存原理

a.

对于直接赋值的这种创建字符串的方式

串池是在堆区的

第一次(也就是s1那行),首先会到串池中去找“abc”,没找到,所以在创建“abc”,并把地址赋值给s1

第二次(s2那行),首先到串池中找”abc“,找到了,直接把地址赋值给s2.(存在复用)

b.

对于new的方式,是直接在堆区创建空间来存储来存储字符串,不存在复用

(4)字符串的比较

==号比较的其实是变量小空间里面记录的东西,基本数据类型就是真实的值,引用数据类型就是地址

(5)字符串的遍历

2.stringbuilder(进行字符串的拼接以及反转时用)

直接print springbuild类型的对象时,打印出的是其内的内容

append方法是在容器后面追加内容

3.stringjoiner(用于拼接字符串,比stringbuilder更加方便,可以指定开始结束以及间隔符号)

4.字符串拼接的底层原理

(1)拼接的时候没有变量

拼接时如果没有变量参与,则编译之后直接就是拼接的结果,那么该代码运行时也就不需要进行拼接了

(2)拼接的时候有变量(jdk8以前)

对于第二行代码,执行过程相当于篮筐里的那行代码(tostring底层是new一个新的字符串)

(3)拼接的时候有变量(jdk8以后的拼接)

他会预估s4的长度,预估为3,然后把abc分别放入数组,然后根据数组来创建字符串(new出来的)

(在jdk8以前,这里是先进行s1与s2的拼接,使用stringbuilder以及tostring,然后进行s1与s2的拼接结果与s3进行拼接 )

即使如此,在进行拼接时依然很浪费时间,在下图情况下,s2会进行一个长度的评估,创建数组以及创建字符串,s3又会发生一轮

因此,以后进行字符串拼接时,还是用stringbuilder或stringjoiner的append好。

(3)stringbuilder

提高拼接效率的原理图(此时串池里有"a""b""c")

stringbuilder源码

stringbuilder初始有一个长度为16的字节(byte类型)数组,当往里面append数据时,实际上是往字节数组里添加对应的ascii码

当添加的字符数小于16时,字节数组无需扩容;

当字符数大于16小于等于34时,数组扩容为16*2+2 ?

当字符数大于34时,数组扩容为字符数

二、集合

1.特点

(1)自动扩容,自动缩小(长度和内容一致)

(2)只能存引用数据类型(要存整数等要存其对应的包装类)

2.集合的种类

(1)arraylist

<String>是泛型,限制arraylist里面只能存储string类型

三、静态

1.静态变量

内存原理

student的字节码文件被放入方法区之后,堆中的静态区里面存放着静态变量(内存中只有一份)

因为静态变量是随着类而加载的,优先于对象出现

可以通过对象找到静态变量

2.静态方法

(1)三种类:

javabean类:私有化成员变量,写无参构造和带全部参数的构造,写get set方法,以及额外方法

工具类:私有化构造方法,使得无法创建该类对象,因为没有意义

所有方法都定义为静态方法

(2)

(3)静态方法的细节

非静态成员方法中是有this变量的,如下图,this是一个方法所在类型的形参,由虚拟机自动赋值(调用者的地址)

在一个成员方法内调用另一个成员变量或成员方法时,调用处(如下图的show2()),前面默认带一个this

而在静态方法中是没有this关键字的

内存角度:

a.静态方法调用非静态变量会出错

执行main中的第一行代码时,首先把student字节码文件加载到方法区,同时静态变量放到静态区

执行第二行时,会到静态区中寻找name和teachername,但是name找不到,因为他不是静态变量,于是出错。

b.非静态能够访问所有静态

对于show()方法,由s1调用,那方法内部就可以根据s1对象来找到anme和teachername,也能通过s1找到该类的所有方法,包括method()。

(4)重识main方法

四、继承

(1)基础知识

设计真实的继承关系时,用画图的方法来解决:

把所有类型放到最底层,然后不断抽取共性(共性在子类中直接删除即可)形成父类

写代码时,直接按照图来写就行,每个类应该包含的属性以及方法就是该类的圈里面所包含的东西

(2)继承内容

a.构造方法

构造方法是一定不能继承的

b.变量

所有的成员变量都是可以继承下来的,只不过private类型的变量子类不能直接使用,但可以通过父类提供的get set方法来间接使用

执行过程内存过程如下:

首先将teststudent类的字节码文件调入方法区,然后main函数进栈开始执行,执行第一行代码时,zi的字节码文件,及其父类fu的字节码文件 ,以及fu的父类object类的字节码(进入顺序是先父类再子类)都会进入方法区,创建zi类对象时,对象区域分为两块,一块是zi自己的属性,一块是fu的属性,之后通过z.访问zi对象的属性时,首先到zi自己的属性中去找,找不到就到fu的属性中去找

对于这种private修饰的情况,使用z.name是找不到继承下来的name(以及age)变量的

c.成员方法

父类把自己虚方法(即非private,非static,非final)放进虚方法表,继承时,子类会拿到该虚方法表并把自己的虚方法添加进去

子类调用父类虚方法时,直接就能在虚方法表内找到,如果不是虚方法,则一级一级的向上找,先找a,再找b,再找c

比如:执行zishow()时,是虚方法(即使是自己的方法),直接在虚方法表内找到

执行fushow2()时,发现不是虚方法,则先找zi,再找fu,发现是private方法,直接报错

(3)继承中的访问特点

a.成员变量

方法中单写name符合就近原则:先局部变量,后本类变量,最后 父类变量

b.成员方法

也是就近原则

使用this.调用时,在本类找方法,再到父类

使用super.调用时,直接到父类找

方法重写相关知识

重写方法的上面要加@override,虚拟机看到会检查重写的格式是否正确,出错会标注红色波浪线

子类重写父类方法时,本质就是 子类方法会覆盖虚方法表中父类同名方法

只要记住45两点即可

c.构造方法

也就是说子类的构造方法一定要先调用父类的构造方法

(4)this与super

注意这里的this(......),他是去调用本类的有参构造,使得使用无参构造创建对象时,无参构造使用有参构造完成成员变量的初始化

当在构造方法写入this(....)(它必须是放在第一行的,否则会报错)时,就没有默认的super()了,因为他所调用的有参构造中有super()

(5)其他细节

子类中,带全部参数的构造,全部参数指的是子类以及父类中所有的参数,父类中参数的初始化调用父类的有参构造来实现

五、多态

1.多态的前提

父类变量可以接受直接子类或间接子类对象

多态是:

当父类有show方法,且子类都重写show方法,父类变量接受子类对象的情况下,父类变量.show调用的是对应子类中重写的show()方法

(2)多态的调用特点

java中,加载字节码文件进方法区时,永远是先加载父类的字节码文件再加载子类的

父类有name变量,子类中自己又定义了一个name变量时,那子类中是有两个name变量的

内存原理

java中,加载字节码文件时,永远是先加载父类的字节码文件再加载子类的,这个例子中,加载顺序为object,animal,dog,dog的字节码文件记录着其父类animal字节码文件的地址

访问a.name时,直接到父类的空间中去找name,而不去子类的空间

(3)多态缺点

父类变量接受子类对象(子类对象会默认转换为父类,属于自动转换)时,无法调用子类特有的方法,但是可以把该对象转换为原类型(属于强转),再去访问该方法

强转前先用instanceof判断下更好

a instanceof dog的作用是判断a是不是dog类的对象,返回true或false

六、一些知识点

1.包

全类名/全限定名就是包名加类名

可以通过导包的方式指定使用的student类是itheima包下的,也可以使用全类名

使用类时要注意的问题

2.final修饰符

final修饰的变量在定义时一定要赋值且以后都不能再赋值

也就是说final修饰的变量里面存储的东西是不能改变的(基本数据类型是数据,引用数据类型是地址)

3.权限修饰符

4.代码块

(1)局部代码块(基本淘汰)

作用就是提前结束变量的生命周期(变量只在所属大括号存在),不过现在已经不用了,因为现在内存很大了

(2)构造代码块(基本淘汰)

构造代码块会在创建对象时优先于构造方法执行,可用于存放构造方法们共性的内容

(3)静态代码块

当类加载到内存时,静态代码块自动执行唯一一次(可用于做数据的初始化,比如可以初始化本类的静态变量)

5.抽象类

父类中无法确定方法体就把方法定义为抽象的

有抽象方法的类必须定义为抽象类

抽象方法虽说不能实例化,但是他的构造方法仍然是有意义的,比如子类可以用其构造方法进行父类属性的赋值

七、接口

实现了接口的类都可以传递给接口变量,此时满足:方法编译看左边,运行看右边。
变量编译和运行都看左边。

1.接口的定义和使用

2.接口中的成员特点

接口.变量名可以访问接口里的变量

无论是什么版本的jdk,接口里的成员方法都默认为public static

3.接口和类之间的关系

当一个类实现多个接口且有同名方法时(比如a接口有方法1,2,3,b接口有方法1,2,3,4),把同名方法(1,2,3)重写一次即可(这个重写即使a中的1,2,3的重写,又是b中的)

当接口a有抽象方法1,接口b有抽象方法2且继承了接口a,接口b的实现类要重写方法1,2

4.扩展

a.jdk8开始接口新增的方法

下面的default和static方法对应上述的第二条,public可以省略,因为默认就是public修饰,default和static不能省略,如果省略了默认为abstract

静态方法不能重写,如果强行写个同名的静态方法也不叫重写

b.jdk9的新特性

这两种私有方法的作用就是给接口内的其他方法去访问,不给外界使用,不用static的给default方法使用,有static的给static方法使用

5.接口的适配器

八、内部类

1.内部类的定义

2.内部类的分类

前三种能看懂即可,不重要

a.成员内部类

成员位置指的是类中,方法外且不被static修饰

private修饰的成员内部类,只能被对应的外部类创建对象,默认的能被本包的类创建对象,和变量的访问原则是相同的

当内部类被private修饰时,可以有外部类提供获取内部类对象的方法,其他类通过使用外部类提供的方法来获取对象,但此时被赋值变量的类型不能写 外部类.内部类,可以写父类object

同名变量的情况

内部类对象中有外部类对象的地址值,outer.this就是内部类对象中的this

b.静态内部类(静态内部类和静态变量使用方式很类似,都可以通过类名.直接拿到)

定义:成员内部类被static修饰就是静态内部类

下图所示为静态内部类访问外部类的静态与非静态属性的演示,静态内部类的方法(无论是静态还是非静态),都只能访问外部类的静态

c.局部内部类

能修饰局部变量的就能修饰局部内部类(比如final),不能则不能(比如public,private)

下图是对上图第三点的解释

外部类中有个属性b,通过外部类的对象调用show方法,方法内部类的对象的方法可以访问到外部类的属性b,也可以访问到show方法的局部变量

d.匿名内部类(某个类只使用一次时就可以写成匿名内部类)

以下格式的含义是:创建了一个对象,这个对象实现了inter接口或者继承了某个类,类体就是大括号的内容,()指的是创建对象时使用的是空参构造

匿名内部类本质上长下面这样(这个例子中swim接口中又swim抽象方法)