ホームページ  >  記事  >  Java  >  Java の基本の復習: 基本的なデータ型と String 型

Java の基本の復習: 基本的なデータ型と String 型

php是最好的语言
php是最好的语言オリジナル
2018-08-02 14:53:272148ブラウズ

1. 基本データ型

Java には、4 つの整数型 (byte、short、int、long)、2 つの 10 進数型 (float、double)、および 1 つの文字型 (char) の 8 つの基本データ型があります。 )、ブール型 (boolean)

type byte value range
byte 1 -2^7 ~ 2^7 - 1
短い 2 -2^15 ~ 2^15 - 1
int 4 -2^31 ~ 2^31 - 1
long 8 -2^63 ~ 2^ 63 - 1

(1 バイトは 8 ビットのバイナリを表します) float は 32 ビット、double は 64 ビット、char は 16 ビット、boolean は 1 ビットを占有します

Java はオブジェクト指向言語であるため、これら 8 つの基本データ型には対応するものがありますパッケージ化クラス: Byte、Short、Integer、Long、Float、Double、Character、Boolean。 これら 8 つの基本タイプとそれに対応するパッケージング タイプ間の割り当ては、自動ボックス化およびボックス化解除を使用して完了します。

Integer a = 1; // 基本数据类型int自动装箱为Integer包装类(实际上在编译时会调用Integer .valueOf方法来装箱)int b = a;  // 自动拆箱(实际上会在编译调用intValue)
では、new Integer(123)Integer.valueOf(123) の違いは何でしょうか?

new Integer(123) は毎回オブジェクトを作成し、Integer.valueOf(123) はキャッシュ オブジェクトを使用するため、Integer.valueOf は複数回使用されます ( 123) の場合、同じオブジェクトへの参照のみが取得されます。 new Integer(123)Integer.valueOf(123) 有什么区别?

new Integer(123) 每次都会创建一个对象,而 Integer.valueOf(123) 使用到了缓存对象,因此多次使用Integer.valueOf(123) 时,只会取得同一个对象的引用。

Integer a = new Integer(123);Integer b = new Integer(123);
System.out.println(x == y);    // falseInteger c = Integer.valueOf(123);Integer d = Integer.valueOf(123);
System.out.println(z == k);   // true

编译器会在自动装箱过程调用 valueOf() 方法,因此多个 Integer 实例使用自动装箱来创建并且值相同,那么就会引用相同的对象。

Integer m = 123;Integer n = 123;
System.out.println(m == n); // true

根据查看Integer类的源码发现,使用valueOf()时,先判断值是否在缓存池中,如果在的话就直接返回缓存池的内容。

public static Integer valueOf(int i) {    if (i >= IntegerCache.low && i <= IntegerCache.high)        return IntegerCache.cache[i + (-IntegerCache.low)];    return new Integer(i);
}

但是看下面的代码

    Integer i1 = 128;    Integer i2 = 128;
    System.out.println(i1 == i2); //false

发现返回的是false,这是因为在Integer中,缓存池的范围为: -128 ~ 127

private static class IntegerCache {
        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;
        }        private IntegerCache() {}
    }

2.String类型

除了上面的八个基本数据类型,String类也是在写程序中最常用的一种类型。

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[];

String.intern()

使用 String.intern() 可以保证相同内容的字符串变量引用相同的内存对象。

下面示例中,s1 和 s2 采用 new String() 的方式新建了两个不同对象,而 s3 是通过 s1.intern() 方法取得一个对象引用,这个方法首先把 s1 引用的对象放到 String Pool(字符串常量池)中,然后返回这个对象引用。因此 s3 和 s1 引用的是同一个字符串常量池的对象。

String s1 = new String("aaa");String s2 = new String("aaa");
System.out.println(s1 == s2);           // falseString s3 = s1.intern();
System.out.println(s1.intern() == s3);  // true

如果是采用 “bbb” 这种使用双引号的形式创建字符串实例,会自动地将新建的对象放入 String Pool 中。

String s4 = "bbb";String s5 = "bbb";
System.out.println(s4 == s5);  // true

在 Java 7 之前,字符串常量池被放在运行时常量池中,它属于永久代。而在 Java 7,字符串常量池被放在堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。

那么知道String不可变性,那这样设计有什么好处呢?

1.字符串池的需要

字符串常量池(String intern pool) 是Java堆内存中一个特殊的存储区域, 当创建一个String对象时。假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。
Java の基本の復習: 基本的なデータ型と String 型

2.允许String对象缓存HashCode

Java中String对象的哈希码被频繁地使用, 比如在hashMap 等容器中。

字符串不变性保证了hash码的唯一性,因此可以放心地进行缓存。这也是一种性能优化手段,意味着不必每次都去计算新的哈希码

3.安全性

String被许多的Java类(库)用来当做参数,例如 网络连接地址URL,文件路径path,还有反射机制所需要的String参数等,假若String不是固定不变的,将会引起各种安全隐患。

boolean connect(string s){  
    if (!isSecure(s)) {   
throw new SecurityException();   
}  
    // 如果在其他地方可以修改String,那么此处就会引起各种预料不到的问题/错误   
    causeProblem(s);  
}

4.线程安全

String 不可变性天生具备线程安全,可以在多个线程中安全地使用。

这篇文章有详细的介绍。

String是不可变,那么有没有可变的字符串呢?

在Java中提供了StringBufferStringBuilder,是可变的。在String中,定义的是一个final字符数组,所以不可变,而StringBuffer和StringBuilder因为继承了AbstractStringBuilder,根据源码可看出是一个可变的字符数组。

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence{
     AbstractStringBuilder(int capacity) {
            value = new char[capacity];
        }    /**
     * The value is used for character storage.
     */
    char[] value;

根据源码还可以知道,StringBuffer是线程安全的,其中的方法都被synchronizedrrreee

コンパイラはオートボックス化プロセス中に valueOf() メソッドを呼び出すため、オートボックス化を使用して複数の Integer インスタンスが作成され、同じ値を持つ場合、それらは同じオブジェクトを参照します。

rrreee

Integer クラスのソース コードを見ると、valueOf() を使用するときに、まず値がキャッシュ プールにあるかどうかを判断し、キャッシュ プールに存在する場合は直接その値を返すことがわかりました。キャッシュプールの内容。

rrreeeしかし、以下のコードを見るとrrreee

、これは整数のキャッシュプールの範囲が -128 ~ 127 であるためです

rrreee

2.String 型

。上記に加えて、8 つの基本データ型の中で、String クラスはプログラムを作成する際に最もよく使用される型でもあります。 Stringクラスはfinal宣言されているため継承できません。データを格納するために内部的に char 配列を使用します。配列は Final として宣言されます。つまり、値配列が初期化された後は他の配列を参照できず、値配列を変更する String の内部メソッドがないため、String を使用できます。不変であることが保証されています。

rrreee

String.intern()🎜🎜🎜 String.intern() を使用すると、同じ内容の文字列変数が同じメモリ オブジェクトを参照するようにできます。 🎜🎜 次の例では、s1 と s2 は new String() を使用して 2 つの新しいオブジェクトを作成し、s3 は s1.intern() メソッドを通じてオブジェクト参照を取得します。このメソッドは、最初に s1 によって参照されるオブジェクトを String Pool に入れます。 (文字列定数プール) を返し、このオブジェクト参照を返します。したがって、s3 と s1 は同じ文字列定数プール オブジェクトを参照します。 🎜rrreee🎜「bbb」を使用して二重引用符を使用して文字列インスタンスを作成すると、新しく作成されたオブジェクトは自動的に文字列プールに入れられます。 🎜rrreee🎜 Java 7 より前では、文字列定数プールは永続世代に属するランタイム定数プールに配置されていました。 Java 7 では、文字列定数プールはヒープ上に配置されます。これは、永続世代のスペースが限られているため、文字列が広範囲に使用されるシナリオでは OutOfMemoryError エラーが発生する可能性があるためです。 🎜🎜では、String が不変であることがわかった場合、このように設計する利点は何でしょうか? 🎜🎜🎜1. 文字列プールの必要性🎜🎜🎜文字列定数プール (String intern pool) は、String オブジェクトが作成されるときの Java ヒープ メモリ内の特別な記憶領域です。この文字列値が定数プールにすでに存在する場合、新しいオブジェクトは作成されませんが、既存のオブジェクトが参照されます。 🎜Java の基本の復習: 基本的なデータ型と String 型🎜🎜🎜2 .String オブジェクトに HashCode のキャッシュを許可する🎜🎜🎜 Java の String オブジェクトのハッシュ コードは、hashMap などのコンテナーなどで頻繁に使用されます。 🎜🎜文字列の不変性によりハッシュ コードの一意性が保証されるため、安心してキャッシュできます。これはパフォーマンスの最適化方法でもあり、毎回新しいハッシュ コードを計算する必要がないことを意味します🎜🎜🎜3. セキュリティ🎜🎜🎜文字列は、ネットワークなどの多くの Java クラス (ライブラリ) によってパラメーターとして使用されます。接続アドレス URL 、ファイルパス path、リフレクション機構に必要な String パラメータなど。 String が固定されていないと、さまざまなセキュリティリスクが発生します。 🎜rrreee🎜🎜4. スレッド セーフ🎜🎜🎜文字列の不変性は本質的にスレッドセーフであり、複数のスレッドで安全に使用できます。 🎜🎜こちらの記事で詳しく紹介しています。 🎜🎜文字列は不変ですが、変更可能な文字列はありますか? 🎜🎜Javaでは、可変の🎜StringBuffer🎜と🎜StringBuilder🎜が提供されています。 Stringでは最終的な文字配列が定義されているのでimmutableですが、StringBufferとStringBuilderは🎜AbstractStringBuilder🎜を継承しているため、ソースコードからは可変文字配列であることが分かります。 🎜rrreeerrreee🎜 ソース コードによれば、StringBuffer がスレッド セーフであり、そのメソッドはすべて synchronized によって変更されていることもわかります。 🎜🎜関連記事: 🎜🎜🎜JavaScriptの基礎知識のデータ型_基礎知識🎜🎜🎜🎜Javaの基本的なデータ型とストリーム🎜🎜🎜関連動画: 🎜🎜

データ型の概要と分類 - JAVA 初心者向けビデオチュートリアル

以上がJava の基本の復習: 基本的なデータ型と String 型の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。