Java基础——Java基础语法

目录

1. 基础类型和包装类

1.1 基本数据类型总结

1.2 包装类的缓冲池:

2. String

2.1 String被final修饰,指向的地址不可变

2.2 字符串常量池

2.3 String, StringBuffer and StringBuilder

2.4 string的常用方法

3. 运算

3.1 参数传递

3.2 隐式类型转换

 

4. object通用方法

4.1 hashCode

4.2 equals

4.3 toString

4.4 clone

4.5 线程相关方法

5. 关键字

5.1 final

5.2 static

6 反射

7. 异常

8. 泛型

9. java 8 的新特性


1. 基础类型和包装类

1.1 基本数据类型总结

Java中8种基本数据类型总结

序号

数据类型

大小/位

包装类

默认值

可表示数据范围

1

byte(位)

8

Byte

0

-128~127|   -2^7  ~  2^7-1

2

short(短整数)

16

Short

0

-32768~32767

3

int(整数)

32

Integer

0

-2147483648~2147483647

4

long(长整数)

64

Long

0

-9223372036854775808~9223372036854775807

5

float(单精度)

32

Float

0.0

1.4E-45~3.4028235E38

6

double(双精度)

64

Double

0.0

4.9E-324~1.7976931348623157E308

7

char(字符)

16

Character

0~65535

8

boolean

8

Boolean

flase

true或false

以int 类型为例 :装箱,调用的是Integer.valueOf();拆箱调用的是  X.intValue();

1.2 包装类的缓冲池:

new Integer(123) 与 Integer.valueOf(123) 的区别在于:

  • new Integer(123) 每次都会新建一个对象;
  • Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。

类型对应的缓冲池如下:

  • boolean values true and false
  • all byte values
  • short values between -128 and 127
  • int values between -128 and 127
  • char in the range \u0000 to \u007F

jdk1.8中Integer 的缓冲池 IntegerCache 很特殊,在启动 jvm 的时候,通过 -XX:AutoBoxCacheMax=<size> 来指定这个缓冲池的大小。

拆装箱Java api文档

Java自动装箱与拆箱及其陷阱

 

2. String

2.1 String被final修饰,指向的地址不可变

String 被声明为 final,因此它不可被继承。(Integer 等包装类也不能被继承)

在 Java 8 中,String 内部使用 char 数组存储数据。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
}
value 数组被声明为 final,该数组初始化之后就不能再引用其它数组。
String 类内部没有改变 value 数组的方法,因此可以保证 String 不可变。

在 Java 9 之后,String 类的实现改用 byte 数组存储字符串,同时使用 coder 来标识使用了哪种编码。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final byte[] value;

    /** The identifier of the encoding used to encode the bytes in {@code value}. */
    private final byte coder;
}

从 Java 7 开始,可以在 switch 条件判断语句中使用 String 对象。但是太复杂的判断还是用if比较好

String 不可变的好处:

  •  String 的 hash 值经常被使用。例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。(hashcode是根据对象地址计算的)
  • 字符串常量池的需要。在程序当中直接写上双引号的字符串就在常量池当中,只有string地址不可变,新创建的string常量才能去常量池找到那个引用。(字符串常量池是在堆当中的)Java中的字符串常量池详细介绍
  • 安全性:String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 对象的那一方以为现在连接的是其它主机,而实际情况却不一定是。【还不太懂,后续补充】
  • 线程安全:String 不可变性天生具备线程安全,可以在多个线程中安全地使用。

例: String s = "abc";s这个变量的指针是指向"abc"这个字符串在内存中的首地址,执行s = "d"的时候,s所指向的内存地址发生了变化,已经不是指向"abc"的首地址,而是把"d"存在内存中,把s的指针指向了"d"的地址

2.2 字符串常量池

字符串常量池(String Pool)保存着所有字符串字面量(literal strings),这些字面量在编译时期就确定。不仅如此,还可以使用 String 的 intern() 方法在运行过程中将字符串添加到 String Pool 中。Java 7 之后,保存在中。

当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。

在 Java 7 之前,String Pool 被放在运行时常量池中,它属于永久代(方法区)[ 方法区和永久代又有着本质的区别。前者是 JVM 的规范,而后者则是 JVM 规范的一种实现 ]。而在 Java 7,String Pool 被移到堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。[ Java 8 中 永久代被元空间取代 Java8内存模型—永久代(PermGen)和元空间(Metaspace)]

例:注意String x = "1"; String m = x.intern()和String y = new String("1");的区别。前者会在常量池找是否有该字符串,后者直接新建对象。

String x="i";String m = x.intern();的方式,Java 虚拟机会将其分配到常量池中;而 String x=new String("i") 则会被分到堆内存中。

String x = "1";
String y ="1";
String z = new String("1");
String m = x.intern();
System.out.println(x==y); //true
System.out.println(y == z); //false
System.out.println(y.equals(z)); //true
System.out.println(x == m);//true

2.3 String, StringBuffer and StringBuilder

三者的区别:

String:不可变字符串; 初始化可以赋值为null.

StringBuffer:可变字符串、效率低、线程安全;初始化为空时,运行报错NullPointerException

StringBuilder:可变字符序列、效率高、线程不安全;初始化为空时,运行报错NullPointerException

2.4 string的常用方法

  • indexOf():返回指定字符的索引。
  • charAt():返回指定索引处的字符。
  • replace():字符串替换。
  • trim():去除字符串两端空白。
  • split():分割字符串,返回一个分割后的字符串数组。
  • getBytes():返回字符串的 byte 类型数组。
  • length():返回字符串长度。
  • toLowerCase():将字符串转成小写字母。
  • toUpperCase():将字符串转成大写字符。
  • substring():截取字符串。
  • equals():字符串比较。

 

3. 运算

3.1 参数传递

Java 的参数是以值传递的形式传入方法中,而不是引用传递。

基本数据类型为参数,将对象的值传递到形参;引用类型为参数,将对象的地址以值的方式传递到形参中;

3.2 隐式类型转换

因为字面量 1 是 int 类型,它比 short 类型精度要高,因此不能隐式地将 int 类型下转型为 short 类型。

short s1 = 1;
// s1 = s1 + 1;  //编译报错add cast to short
s1 += 1;         //相当于 s1 = (short) (s1 + 1);
// s1++;

 

4. object通用方法

public native int hashCode()

public boolean equals(Object obj)

protected native Object clone() throws CloneNotSupportedException

public String toString()

public final native Class<?> getClass()

protected void finalize() throws Throwable {}

public final native void notify()

public final native void notifyAll()

public final native void wait(long timeout) throws InterruptedException

public final void wait(long timeout, int nanos) throws InterruptedException

public final void wait() throws InterruptedException

4.1 hashCode

hashCode() 返回散列值,而 equals() 是用来判断两个对象是否等价。

equals()==true,则hashCode()相等;hashCode()相等不一定equals()=trure(即发生了hash冲突)。

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

如果不重写hashcode,对hashMap的影响是,本来相等的两个值得hashcode不相同,导致输入数据重复。

Java中hash算法细述

4.2 equals

  • 对于基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。
  • 对于引用类型,== 判断两个变量是否引用同一个对象,而 equals() 判断引用的对象是否等价。
  • 对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false

声明一个类,通常都要重写equals和hashcode方法

重写equals方法的步骤:

  • 检查是否为同一个对象的引用,如果是直接返回 true;
  • 检查是否是同一个类型,如果不是,直接返回 false;
  • 将 Object 对象进行转型;
  • 判断每个关键域是否相等。

重写hashcode方法的步骤:

散列函数要把所有域的值都考虑进来。可以将每个域都当成 R 进制的某一位,然后组成一个 R 进制的整数。R 一般取 31,因为它是一个奇素数,如果是偶数的话,当出现乘法溢出,信息就会丢失,因为与 2 相乘相当于向左移一位。

public class EqualExample {

    private int x;
    private int y;
    private int z;

    public EqualExample(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        EqualExample that = (EqualExample) o;

        if (x != that.x) return false;
        if (y != that.y) return false;
        return z == that.z;
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + x;
        result = 31 * result + y;
        result = 31 * result + z;
        return result;
    }
}

4.3 toString

默认返回 className@4554617c 这种形式,其中 @ 后面的数值为散列码的无符号十六进制表示。

可以根据需要 重写一下

4.4 clone

clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。

Cloneable 接口规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。应该注意的是,clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。

浅拷贝:拷贝对象和原始对象的引用类型引用同一个对象。(新建的对象引用还是指向原来的对象)

深拷贝:拷贝对象和原始对象的引用类型引用不同对象。(拷贝的时候新建了一个对象)

不推荐使用clone方法。可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。

public class CloneConstructorExample {

    private int[] arr;

    public CloneConstructorExample() {
        arr = new int[10];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i;
        }
    }

//拷贝构造函数
    public CloneConstructorExample(CloneConstructorExample original) {
        arr = new int[original.arr.length];
        for (int i = 0; i < original.arr.length; i++) {
            arr[i] = original.arr[i];
        }
    }

    public void set(int index, int value) {
        arr[index] = value;
    }

    public int get(int index) {
        return arr[index];
    }
}

4.5 线程相关方法

方法作用
wait线程自动释放占有的对象锁,并等待notify。
notify随机唤醒一个正在wait当前对象的线程,并让被唤醒的线程拿到对象锁
notifyAll唤醒所有正在wait当前对象的线程,但是被唤醒的线程会再次去竞争对象锁。因为一次只有一个线程能拿到锁,所有其他没有拿到锁的线程会被阻塞。推荐使用。

Java中wait、notify、notifyAll使用详解

 

5. 关键字

5.1 final

  • final 修饰的类叫最终类,该类不能被继承。
  • final 修饰的方法不能被重写。

private 方法隐式地被指定为 final,如果在子类中定义的方法和基类中的一个 private 方法签名相同,此时子类的方法不是重写基类方法,而是在子类中定义了一个新的方法。

  • final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。

对于基本类型,final 使数值不变;

对于引用类型,final 使引用不变,也就不能引用其它对象,但是被引用的对象本身是可以修改的。

 

5.2 static

1. 静态变量

  • 静态变量:又称为类变量,类所有的实例都共享静态变量,可以直接通过类名来访问它。静态变量在内存中只存在一份。
  • 实例变量:每创建一个实例就会产生一个实例变量,它与该实例同生共死。

2. 静态方法

静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,不能是抽象方法。

只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字。

3. 静态语句块

静态语句块在类初始化时运行一次。

4. 静态内部类

非静态内部类依赖于外部类的实例,而静态内部类不需要。

静态内部类不能访问外部类的非静态的变量和方法。

public class OuterClass {

    class InnerClass {
    }

    static class StaticInnerClass {
    }

    public static void main(String[] args) {
        // InnerClass innerClass = new InnerClass(); // 'OuterClass.this' cannot be referenced from a static context
        OuterClass outerClass = new OuterClass();
        InnerClass innerClass = outerClass.new InnerClass();
        StaticInnerClass staticInnerClass = new StaticInnerClass();
    }
}

5. 初始化顺序

静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序。

存在继承的情况下,初始化顺序为:

  • 父类(静态变量、静态语句块)
  • 子类(静态变量、静态语句块)
  • 父类(实例变量、普通语句块)
  • 父类(构造函数)
  • 子类(实例变量、普通语句块)
  • 子类(构造函数)

6 反射

深入解析Java反射(1) - 基础

7. 异常

Throwable 可以用来表示任何可以作为异常抛出的类,分为两种: Error 和 Exception。其中 Error 用来表示 JVM 无法处理的错误,Exception 分为两种:

  • 受检异常 :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
  • 非受检异常 :是程序运行时错误,例如除 0 会引发 Arithmetic Exception,此时程序崩溃并且无法恢复。

Java入门之异常处理

8. 泛型

泛型防止了强制类型转换情况的发生。

它提供了编译期的类型安全,确保你只能把正确类型的对象放入集合中,避免了在运行时出现ClassCastException。

泛型的工作原理?

    编译器编译时对泛型进行擦除,所以在运行时不存在任何类型相关的信息。例如List<String>在运行时仅用一个List来表示。这样做的目的,是确保能和Java 5之前的版本开发二进制类库进行兼容。

泛型的限定通配符?

<? extends T>确保类型必须是T的子类来设定类型的上界

<? super T>确保类型必须是T的父类来设定类型的下界

<?>表示了非限定通配符,因为<?>可以用任意类型来替代。

9. java 8 的新特性

Java8 新特性

JAVA8新特性(吐血整理)

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值