JavaSE知识点总结(持续更新,欢迎指正)

基础

jvm,jdk,jre

1.字节码

.class文件,相对二进制文件是一种中间文件,只能在虚拟机上运行,也是java可移植性的由来。

2.jvm

Java 虚拟机(JVM)是运行 Java 字节码的虚拟机,会把字节码变成二进制机器码。JVM 有针对不同系统的特定实现(Windows,Linux,macOS)。字节码和不同系统的 JVM 实现是 Java 语言“一次编译,随处可以运行”的关键所在。

3.jdk和jre:

顾名思义,jdk为工具,javac命令等。jre为运行环境

jdk包含jre,运行程序只要jre,开发需要jdk。

那些东西会被继承

1.成员变量和成员方法

父类private的不会被继承。

private以上都可被继承

2.类变量和类方法

同成员变量

3.构造方法

构造函数不能继承

ps:无法继承的东西是拥有的,只是无法访问

重载和重写,多态

1.重载

方法名必须相同(显然)

三者必有一:参数列表必须有不同之处(顺序,个数,类型)(重载的意义所在

方法返回值和访问修饰符可以不同。(扩展)

2.重写

方法名必须相同(显然)

参数列表必须相同(和重载相反处

访问修饰符范围大于等于父类;(不然会影响向上转型实现多态

插播多态:

Father father = new Son();
father.method();
1.这里多态体现在哪?
改变赋值为Father father=new Son1()
同样执行father.method();会根据father指向子类不同而多态,method方法的内容呈现多态
继承和接口都能实现多态,手段都是向上转型
2.若method权限被降低,father就不能调用method方法了,向上转型就废了

如果父类方法访问修饰符为 private 则子类就不能重写该方法。(因为根本不继承)

返回值范围小于等于父类,抛出的异常范围小于等于父类(里氏代换原则)

拆箱装箱

Interger it=new Interger(i); 装箱

int i=it.intvaule(); 拆箱

区别是基本类型和引用类型的区别,引用类型有避免空指针的好处

==的自动拆箱问题

例如

 1 public class Main {
 2     public static void main(String[] args) {
 3 
 4         Integer i1 = 100;
 5         Integer i2 = 100;
 6         Integer i3 = 200;
 7         Integer i4 = 200;
 
        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        System.out.println(c==(a+b));//true

 9         System.out.println(i1==i2);  //true
10         System.out.println(i3==i4);  //false
11     }
12 }
总结

1.Integer类创建对象的时候,数值在[-128,127]之间,会返回cache数组中的已经存在的对象的引用。

2.包装类的"= ="运算只在遇到算术运算的情况下会自动拆箱,如a==b+c

3.当a和b在[-128,127],a= =b也可能成立(a在数值上=b),看起来和2矛盾,但是结合1即知是因为是返回缓存的地址。

== 与 equals

对象的==和equals

1.==

基本数据类型比较的是值,引用数据类型比较的是内存地址

2.equals

**没被重写等效==,**重写了可以实现别的效果。

我们很熟悉的equals判断字符串内容就是String类重写了方法。

hashCode 与 equals

上面说equals判断字符串内容就是String类重写了equals方法,有那么简单吗?实际上重写 equals 时还必须重写 hashCode 方法!

1.我们先介绍hashCode

1.hashCode() 是 Object.类的方法,作用是获取对象的哈希码。

2.哈希码是hashCode() 对堆上的对象产生独特值,利用的是内存地址。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等。

2.为什么要hashcode?

假设,HashSet中已经有1000个元素。当插入第1001个元素时,需要怎么处理? “将第1001个元素逐个的和前面1000个元素进行比较”?显然,这个效率是相等低下的。

HashSet 如何检查重复:

它使用哈希算法根据元素的hashcode计算出元素在散列表中的位置,如果位置上有对象,进行equals比较(判断对象是否真的相同),因为不同的key求hash是可能产生hash碰撞的),两次判断都相同才视为相同对象(equals不同会放到一个桶内)成功插入,否则不插入。这样的方法避免了一个大循环,速度upup。

简而言之hashcode只是在散列表中应用来缩短查找时间(求hash的时间复杂度是O(1),比遍历快多了),判重还得看equals,对象hashcode相同并不一定相同,可能哈希冲突。

3.为什么重写 equals 时必须重写 hashCode 方法

简单地说就是保证两者判重的逻辑一致即分别调用equals和hashcode时要返回结果相同(只需要对象会用Hashset存储时才有这个要求)

看hashmap源码可知散列表是会通过hashcode确定数组下标,再用equal判重的。假设你认为a和b是同一个对象,但是只重写equal使两者相同,而hashcode不同。根据hashmap源码连数组下标都不会一样,根本轮不到equal方法调用就会被Hashset当成不同的对象,和你认为的矛盾。

举例:当我们重写equals为属性name相同就相同时,我们hashcode方法应该重写为name相同hashcode就相同。

java值引用

java只有值引用,基本数据类型传递值,引用类型传递引用,都是传递值。

深拷贝 vs 浅拷贝

1.深拷贝,涉及new开辟内存,拷贝内存数据

new b

b.1=a.1;

b.2=a.2;

2.浅拷贝,拷贝引用

a=b

3.ps:集合框架可通过new(tmp)实现深拷贝,这是源码帮我们实现的

4.clone方法

对当前对象浅拷贝。

那么如何深拷贝呢?(1比较方便)

1.序列化这个对象再序列化回来,引出5

2.重写clone方法

5.什么是序列化

即将对象写到IO流中,变成字节的序列

好处是:这些字节序列相比对象

1.能保存在磁盘上

2.可以通过网络传输(所有网络上传输的对象都需要能序列化

6.为什么实现Serializbale接口就能够进行序列化?

Serializbale接口和RandomAccess接口原理基本相同,起标识类的作用。别的方法使用这些类的时候,会用instanceof检查是不是标识类的子类,然后采取不同的措施。

1.对于Serializbale,不是则报错

2.对于RandomAccess,不是则不会使用随机存储访问的方法,换用链式储存的方法

字符型常量和字符串常量的区别?

  1. 含义上: 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)。换句话,char是基本数据类型,而String是引用数据类型。
  2. 注意: char 在 Java 中占两个字节

String对象创建过程

当创建 String 类型的对象时,虚拟机会在==常量池(因为String字符串内容是不变的)==中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。

Object对象有那些方法(看过源码)

1.clone方法

实现Cloneable接口才能调用该方法

2.getClass

运行时获得类型

3.toString

String地址

4.finalize

用于释放资源,很少用,因为垃圾回收时必执行一次,释放两次资源会报错

5.equls和hashcode

6.wait,notify,notifyAll

当前线程等待该对象的锁,还可以wait(Long timeout)

唤醒对象上等待的某个进程

唤醒对象上等待的所有进程

notify等关于线程的方法为什么放在了object类里?

任何对象都可以被多个线程竞争

StringBuffer,StringBuilder,String对比

1.String

表面:
String的特点是不变性,即String对象的字符串内容是不变的,对String进行操作的函数实质都是产生了一个新的String对象,包括字符串的拼接。

经典考题:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vnmnenTk-1597201197982)(file:///C:\Users\zzz\Documents\Tencent Files\657133058\Image\Group2\JM\M[\JMM[4U6_{EXZRA4$0{T8}`H.jpg)]

答:abc-----xyz

源码:String类中使用final关键字修饰字符数组来保存字符串的内容,所以其是不可变的不可继承的,因为内容被声明成了常量。

2.StringBuffer和StringBuilder比较,和spring比较

相同:
这两种对象都是可变的,原因自然是源码和String相反,没有使用final修饰字符数组。都继承AbstractStringBuilder类,所以API也大致相同。

不同:
线程安全性:buffer是线程安全的,其方法加了同步锁,而builder是线程不安全的。不过自然builder效率略快一些。

和String比:
显而易见有带缓冲区的优势,这个优势也决定了StringBuffer和StringBuilder更加适合大字符串,因为String对象老是会new一个新的String,对大字符串很不友好。反之小量字符串适合String

总之

大数据单线程StringBuilder

大数据多线程StringBuffer

小数据spring

3.StringBuffer的API

1.构造方法
· public StringBuffer() :无参构造方法
· public StringBuffer(int capacity) :指定容量的字符串缓冲区对象
· public StringBuffer(String str) :指定字符串内容的字符串缓冲区对象
2.添加功能
· public StringBuffer append(String str):可以把任意类型数据添加到字符串缓冲区里面,并返回字符串缓冲区本身
· public StringBuffer insert(int offset,String str):在指定位置把任意类型的数据插入到字符串缓冲区里面,并返回字符串缓冲区本身
3.删除功能
· public StringBuffer deleteCharAt(int index):删除指定位置的字符,并返回本身
· public StringBuffer delete(int start,int end):删除从指定位置开始指定位置结束的内容,并返回本身
4.替换功能
· public StringBuffer replace(int start,int end,String str):使用给定String中的字符替换词序列的子字符串中的字符
5.反转和截取:略

super和this

this

1.调用当前实例方法

this()调用对象无参构造函数

2.调用当前实例变量

3.除了和方法参数冲突的情况都是可省的

super

1.调用父类构造方法

super()无参

super(10):自动搜索父类匹配的构造

2.用于访问父类成员变量 number ,调用其父类 的方法。

super.number = 10;

super.showNumber();

Final Finally Finalize

final:

1.类final不可被继承,原理是方法和成员都隐性加上final

2.变量final意味是常量,且必须赋初值

3.方法final不可重写

4.private不可继承的原因可以说是被隐式指定为了final

Finally

try catch后面总是会执行的代码块,可以把释放资源写在这里。注意就算别的地方return都还是会先执行finally块再return

finalize

Object类的方法,垃圾收集器在将对象从内存里面回收时调用的方法,做一些清理工作。重写之可以整合系统其他资源或做一些别的清理工作。

Comparable和Comparator的区别

1.Comparable:内部比较器

继承这个接口后,重写实现compareTo方法,放入treemap等有序集合中即会自动排序。

2.Comparator:外部比较器

类无法修改时,可以使用此外部比较器(内部比较器则要修改类的源代码)。此时在treemap等有序集合中就会通过compare方法的规则重排序。

用法:先sort方法动态绑定这个外部比较器(这里用的Collections工具类,对象.sort也可以)

Collections.sort(arrayList, new Comparator<Integer>() { @Override            
public int compare(Integer o1, Integer o2) {
    return o2.compareTo(o1);            
}        
});

3.集合里面排序的规则

规则:compareTo/compare方法return负数代表降序,正数代表升序。

内部类

广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。

1.匿名内部类的Lambda(常用)

基本的很熟悉了,就是new 接口/抽象类,然后实现方法。讲一下和Lambda结合的方法。Lambda表达式允许使用更简洁的代码来创建只有一个抽象方法的接口(这种接口被称为函数式接口)的实例,完全可以用于简化匿名内部类,因为其方法很多情况only one。

interface C{
    public void getData(int e);
}

public class Anonymous {
    public void test1(A a){
        System.out.println("interface A 的getNum是:  ");
        a.getNum();
    }
    public void test2(C c){
        System.out.println("interface C 的getData是:  " );
        c.getData(10);
    }
    public static void main(String[] args){
        Anonymous an = new Anonymous();
       
       an.test1(new A() {//匿名内部类实现
            public void getNum() {
                System.out.println("A 实现");
            }
        });
        an.test2(new C() {//匿名内部类实现
            public void getData(int e) {
                System.out.println("C 实现");
            }
        });
        
        //Lambda表达式,形参表为空,代码体中直接写方法体
        an.test1(()->{
            System.out.println("A 实现");
                });
        //Lambda表达式,有形参写->前面
        an.test2((c)->{
            System.out.println("C 实现");
        });
    }
}

Lambda表达式更简洁的本质是规定了被继承的接口抽象方法只有一个,那么创建的时候很多东西都确定了,以test2为例子,test2方法参数为接口C,所以类名省略,接口C只有一个方法,所以除了方法体外都省略,剩下的只有具体参数和方法体。

实际应用举例

外部比较器:

 strList.sort((s1, s2) -> (s1 + s2).compareTo(s2 + s1));

等效

strList.sort(new Comparator<String>() {            
    public int compare(String o1, String o2) {
        return (o1 + o2).compareTo(o2 + o1);            
    }   
});

ps:Lambda代码块只有一条return语句,甚至可以省略return关键字。如果代码块只有一条语句,Lambda表达式会自动返回这条表达式的值。所以这里return也省略了。

2.成员内部类

class Circle {    
	double radius = 0;   
    
    public Circle(double radius) {        
    this.radius = radius;    
    }      
    
    class Draw {     
    //内部类        
        public void drawSahpe() {            		 				System.out.println("drawshape");        
        } 
    
    } 
    
}

1.类Draw像是类Circle的一个成员,Circle称为外部类。成员内部类可以无条件访问外部类的所有成员属性和成员方法

2.在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问

3.成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。

4.由于Draw类像一个成员,所以不同于类只有两种修饰权限,它有四种。和成员差不多:private 修饰,则只能在外部类的内部访问,如果用 public 修饰,则任何地方都能访问;如果用 protected 修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。

总是显式定义无参构造而不利用隐式的(super的扩展)

1.我们知道每一个子类的构造方法必调用super方法(帮助子类做初始化工作),先是看有无显式super去调用父类的特定构造。不显式的调用,编译也会自动插入super()调用父类无参构造的。

2.当类无构造方法时,隐式存在一个无参构造。

3.如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用 super()来调用父类中特定的构造方法,则编译时将发生错误。因为我们总是习惯不调用super,所以父类总是显式定义一个无参构造

import java 和 javax 有什么区别?

javax 之前只是扩展 API 包,后面成为了默认的懒得改到java包了。两者都是java自带api。

接口和抽象类的区别是什么?

常规的:

1.方法

接口的方法默认是 public abstract,也只能如此

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值