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抽象方法)