java基础知识进阶

java基础随笔

八大基本类型

数据类型长度包装类默认值
byte1字节Byte0
short2字节Short0
int4字节Integer0
long8字节Long0L
float4字节Float0.0f
double8字节Double0.0d
char2字节Character‘u0000’
boolean1字节Booleanfalse

自动转型

byte->short->char->int->long->float->double

一般来说小地址的能转大地址的。反过来就要强转,但是可能会出现内存溢出。

Integer缓冲池

jvm会创建-128到127的整数,new Integer对象时如果使用:

// 12在 -128到127 从缓冲池取值 a指向常量池
Integer a=12;
//创建对象,b对象里的值指向常量池
Integer b=new Integer(12);
//在堆里开辟空间,129放堆里
Integer c=129;

String类

String内部存储字符串使用的是一个final 修饰的char 数组,这就表示String值不可变;

//String对象指向常量池“qwe”
String a="qwe";
//由于值不可变,这里将a指向"asd";"qwe"就变成了没有对象引用的值
a="asd;"

StringBuilder和StringBuffer

StringBuilder是线程不安全的,并且它是可变长,它的值是用char数组保存,容量不够new一个数组然后拷贝值,将扩容数组引用给原来的数组引用。

StringBuffer是线程安全的,它也是可变长的,和StringBuilder相同,但是它使用了同步块保证自身安全,所以它的效率比StringBuilde低。在单线程首选StringBuilder,多线程用StringBuffer;

equals()

Object类的方法,每个类都有。如果不重写该方法就会使用Object的equals()方法,该方法与“==”运算符等价,会比较两个对象的引用地址转化的字符串。八大基本类型包装类,String类重写了该方法。

所以自定义javabean要比较对象需要重写该方法。

为什么重写equals()要重写hashCode()方法

hashCode() 返回散列值,而 equals() 是用来判断两个对象是否等价。
等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价

在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等

hashCode()介绍

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。

散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)

为什么要有 hashCode

我们先以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode: 当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的Java启蒙书《Head first java》第二版)。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。

通过我们可以看出:hashCode() 的作用就是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。**hashCode()在散列表中才有用,在其它情况下没用。**在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。

hashCode()与equals()的相关规定

  1. 如果两个对象相等,则hashcode一定也是相同的
  2. 两个对象相等,对两个对象分别调用equals方法都返回true
  3. 两个对象有相同的hashcode值,它们也不一定是相等的
  4. 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
  5. hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

多态

父类引用指向子类对象,并重写了父类方法,这样父类引用对象调用同一方法就有不同的效果

对象的创建

  1. new 关键字调用构造方法
  2. 类实现Cloneable接口 调用clone()方法
  3. 反射
  4. 序列化实现Serializable接口

静态块,普通块

创建对象:

  1. 静态变量
  2. 静态块 static{}
  3. 属性
  4. 构造块
  5. 构造方法

普通块:方法内{}

Collections

容器工具类:

  • sort():对传入Collection实现类实例进行排序,前提是容器存放对象实现了Comparator的compare方法。或者传入一个实现Comparable 方法并实现了comparaTo方法
  • 将不安全容器转化线程安全

在这里插入图片描述

lambda

@FunctionalInterface或自定义只有一个方法接口表示的接口可以直接用lambda:(形参名)->{语句}

消费型接口 Comsumer void accept(T t)
供给型接口 Supplier T get()
函数型接口 Function<T,R> R apply(T t)
断定型接口 Predicate boolean test(T t)

容器

Collection

List:

      1. **ArrayList**:内部使用数组存储值,快速查找,不适合频繁插入删除
      2. **LinkedList**:使用双向链表存储,查询效率低,利于频繁插入删除
      3. Queue:队列,是一个接口LinkedList实现了它
      4. Vector:线程安全链表
      5. **HashSet**:使用HashMap的key存储值;

Map:

内部包含了一个 Entry 类型的数组 table。

transient Entry[] table;

Entry 存储着键值对。它包含了四个字段,从 next 字段我们可以看出 Entry 是一个链表。
即数组中的每个位置被当成一个桶,一个桶存放一个链表。HashMap 使用拉链法来解决冲突,
同一个链表中存放哈希值相同的 Entry。

hashMap:内部重写hashCode方法

内部使用Entry节点存储<hash,key,value,下一节点引用>;采用数组加链表形式;初始容量16,负载因子0.75

如果元素个数大于16*0.75,数组长度扩大为原来2倍,重新hash。单条链表大于8就会转化为红黑树。

1.为什么默认初始容量为16(1<<4)

因为位运算直接对内存数据进行操作,不需要转成十进制,所以位运算要比取模运算的效率更高,所以HashMap在计算元素要存放在数组中的index的时候,使用位运算代替了取模运算。之所以可以做等价代替,前提是要求HashMap的容量一定要是2^n

太小了就有可能频繁发生扩容,影响效率。太大了又浪费空间,不划算。

所以,16就作为一个经验值被采用了。

2.java1.8之前采用头插,之后为什么尾插(明明知道HashMap是线程不安全的,为啥还要考虑这个)

在这里插入图片描述

而尾插扩容顺序不会变,不会形成死链。

hashTable:线程安全的Map

线程安全容器方案

1.使用Collections方法synchronizedList(),synchronizedMap(),synchronizedSet(),传入不安全容器返回安全容器。
2. 使用juc(java.utils.concurrent)包下线程安全容器,或Vector,HashTable
3. 自定义一个类封装容器,使用同步方法或者锁来保证数据一致性

多线程

线程创建方式:

  1. 继承Thread类,重写run()方法
  2. 实现Runable接口,实现run()方法
  3. 实现Callable接口,实现call()方法

区别:

1,继承Thread类:由于单继承多实现,它的灵活性不高,但是胜在调用简单。
2, 实现Runable接口:灵活性好
3,实现Callable接口:灵活性好,有返回值,方法可抛出异常,缺点是调用复杂

ThreadLocal

存放当前线程变量,线程结束,自动销毁。存放值形式为Map,key为当前线程对象(线程名字和线程id)。多线程共享一个Runable,但是由于线程不同所以存取的是不同的值。

public class ThreadLocalTest {
    public static void main(String[] args) {
        MyRunable runable=new MyRunable();
        new Thread(runable).start();
        new Thread(runable).start();
    }
}
class MyRunable implements Runnable{
    private ThreadLocal<Integer> local=new ThreadLocal<>();
    @Override
    public void run() {
         for(int i=0;i<3;i++){
             if(local.get()==null){
                 local.set((int) (Math.random()*100));
             }
             System.out.println(Thread.currentThread().getName()+Thread.currentThread().getId()+"ThreadLocal:"+local.get());
              try {
                 Thread.sleep(2);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值