Java基础1——基本类型和关键字

看到一篇写的很好的Java基础的文章,不自己再写一遍的话好像就没有看过一样,方便以后看,有很多东西都是直接copy过来的。最后分享一下原文的链接:原文链接

一、数据类型

1.Java有8种基本数据类型,基本类型都有对应的包装类型,基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。

  • boolean/(1) —— Boolean 没有明确给出占的字节数,只是说明代表true和false两个值
  • byte/8 —— Byte
  • char/16 —— Character
  • short/16 —— Short
  • int/32 —— Integer
  • float/32 —— Float
  • long/64 —— Long
  • double/64 —— Double

2.除了boolean类型外,其他的基本数据类型都可以相互转换。自动转换级别:

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

3.缓冲池

Integer x = new Integer(123);

Integer y = new Integer(123);

System.out.println(x == y);    // false



Integer z = Integer.valueOf(123);

Integer k = Integer.valueOf(123);

System.out.println(z == k);   // true



Integer x = 1;

Integer y = 1;

System.out.println(x==y);  //true

第一种方式每次都会创建一个新的对象,第二种方式会使用缓存池中的对象,多次调用会取得同一个对象的引用,第三种(自动装箱)会自动调用valueOf方法

基本类型对应的缓冲池如下:

  • 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

在使用这些基本类型对应的包装类型时,就可以直接使用缓冲池中的对象。其他基本类型没有缓冲池概念。

 Double a = 1d;
 Double b = 2d;
 System.out.println(a == b); //false

在 Java 8 中,Integer 缓存池的大小默认为 -128~127。

static final int low = -128;
static final int high;
static final Integer cache[];

static {
    // high value may be configured by property
    int h = 127;
    String integerCacheHighPropValue =
        sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
    if (integerCacheHighPropValue != null) {
        try {
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
        } catch( NumberFormatException nfe) {
            // If the property cannot be parsed into an int, ignore it.
        }
    }
    high = h;

    cache = new Integer[(high - low) + 1];
    int j = low;
    for(int k = 0; k < cache.length; k++)
        cache[k] = new Integer(j++);

    // range [-128, 127] must be interned (JLS7 5.1.7)
    assert IntegerCache.high >= 127;
}

从源码中我们可以看出,缓冲池中创建了缓冲池默认大小的对象。

二、String

1.String 被声明为 final,因此它不可被继承。

内部使用 char 数组存储数据,该数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。

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

三、Object 通用方法

1.equals()

(1)该方法具有以下几个特点:自反性、对称性、传递性和一致性,对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false

(2)equals()和==的比较

  • 对于基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。
  • 对于引用类型,== 判断两个变量是否引用同一个对象,而 equals() 判断引用的对象是否等价
Long c = 1l;
System.out.println(c.equals(1)); //false
System.out.println(c==1); //true 会进行自动拆箱操作

Long x = new Long(1);
Long y = new Long(1);
System.out.println(x==y); //false
System.out.println(x.equals(y)); //true

String s = "1";
System.out.println(x.equals(s)); //false
System.out.println(s.equals(x)); //false

AccessToken accessToken = new AccessToken();
accessToken.setAccessToken("1");
AccessToken accessToken1 = new AccessToken();
accessToken1.setAccessToken("1");
System.out.println(accessToken.equals(accessToken1)); //false

我们可以通过源码来看一下为什么会出现这种情况

//Object的实现:
public boolean equals(Object obj) {
        return (this == obj);
}//由此我们可以看出对于自定义类来说,如果没有重写equals方法,它就会调用父类方法,对于对象来说equals比较的仅仅是对象是否是自身比较

//String的实现:
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
}

//Long的实现:
public boolean equals(Object obj) {
        if (obj instanceof Long) {
            return value == ((Long)obj).longValue();
        }
        return false;
}

//从上面两种包装类的实现上我们可以看出,每次在校验两个对象是否是等价时,首先会检查一下是否是同一种数据类型,如果数据类型不同就直接返回false,那么对于上面几种结果我们就可以理解了
//对于重写equals方法的思路跟String是差不多的,首先检查是否是自身比较和是否是同一类型,然后再比较各个域对应的值是否相等

2.hashCode()

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

 3.toString()

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

4.clone()

(1)cloneable

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

public class CloneExample {
    private int a;
    private int b;
}
CloneExample e1 = new CloneExample();
// CloneExample e2 = e1.clone(); // 'clone()' has protected access in 'java.lang.Object'

重写 clone() 得到以下实现:

public class CloneExample {
    private int a;
    private int b;

    @Override
    public CloneExample clone() throws CloneNotSupportedException {
        return (CloneExample)super.clone();
    }
}
CloneExample e1 = new CloneExample();
try {
    CloneExample e2 = e1.clone();
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}
java.lang.CloneNotSupportedException: CloneExample

以上抛出了 CloneNotSupportedException,这是因为 CloneExample 没有实现 Cloneable 接口。

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

public class CloneExample implements Cloneable {
    private int a;
    private int b;

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

(2)浅拷贝

拷贝对象和原始对象的引用类型引用同一个对象,当原始对象修改后,拷贝对象也会修改

(3)深拷贝

拷贝对象和原始对象的引用类型引用不同对象,即当原始设备修改后,拷贝对象不会修改

(4)clone() 的替代方案

使用 clone() 方法来拷贝一个对象即复杂又有风险,它会抛出异常,并且还需要类型转换。Effective Java 书上讲到,最好不要去使用 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];
    }
}
CloneConstructorExample e1 = new CloneConstructorExample();
CloneConstructorExample e2 = new CloneConstructorExample(e1);
e1.set(2, 222);
System.out.println(e2.get(2)); // 2

四、关键字

1.final

(1) 数据   声明数据为常量,可以是编译时常量,也可以是在运行时被初始化后不能被改变的常量。

  • 对于基本类型,final 使数值不变;
  • 对于引用类型,final 使引用不变,也就不能引用其它对象,但是被引用的对象本身是可以修改的。也就是对象的属性值可以修改
final int x = 1;
// x = 2;  // cannot assign value to final variable 'x'
final A y = new A();
y.a = 1;

(2)方法   声明方法不能被子类重写。

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

(3) 类   声明类不允许被继承。

2.static

(1)被static修饰后的字段属性和方法,不需要实例化,直接通过类名就可以直接调用。

静态方法在类加载的时候就存在了,它不依赖于任何实例,所以静态方法必须有实现,也就是说它不能是抽象方法,而且只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字。

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

非静态内部类依赖于外部类的实例,而静态内部类不需要,静态内部类不能访问外部类的非静态的变量和方法。

(2)静态导包

在使用静态变量和方法时不用再指明 ClassName,从而简化代码,但可读性大大降低。

import static com.xxx.ClassName.*

(3)初始化顺序

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

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

  • 父类(静态变量、静态语句块)
  • 子类(静态变量、静态语句块)
  • 父类(实例变量、普通语句块)
  • 父类(构造函数)
  • 子类(实例变量、普通语句块)
  • 子类(构造函数)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值