Java Data Structure: Packaging Classes & Simple Understanding of Generic Classes

life is long so add oil

Table of contents

1. What is a packaging class?

1.1 Packing and unboxing 

 1.2 Automatic boxing and automatic unboxing

 2. What are generics

 3. Export generics

3.1 Grammar 

4 Use of generic classes

4.1 Grammar 

4.2 Example 

4.3 Type Inference 

 5. Raw Type (understand)

5.1 Description

6 How are generics compiled?

 6.1 Erase mechanism

 6.2 Why cannot instantiate a generic type array

7 Upper bound for generics

7.1 Syntax

7.2 Example 

7.3 Complex examples

8 Generic methods 

 8.1 Definition syntax

8.2 Example 

 8.3 Usage examples - type deduction is possible

 8.4 Usage example - no type deduction


1. What is a packaging class?

Wrapper classes refer to a series of classes used in Java to box basic data types into objects. There are eight types of these classes:

1. Byte:           Enclosing byte Basic number Category type
2. Short: ​ ​ Enclosed short Basic number categorization type
3. Integer: ​ Enclosing completed int Basic number deferred type category
4. Long: Enclosed long Basic number fixed type category
5. Float< a i=22>: Enclosed float Basic number fixed type category
6. Double: Enclosed double Basic number fixed type category

7. Character:Enclosed char Basic number Type category

8. boolean: ​ Enclosed boolean Basic number Type category

These classes provide various functions such as converting basic data types to objects, comparing objects, etc. In Java, since basic types do not inherit from Object, in order to support basic types in generic code, Java corresponds to a wrapper type for each basic type.

Note: Except for Integer and Character, the rest are basically The first letter of the type of packaging class is capitalized

1.1 Packing and unboxing 

Boxing (packing): Convert a basic data type into a packaging type.

Unboxing (unpacking): Convert a packed type into a basic data type.

int i = 10;

// 装箱操作,新建一个 Integer 类型对象,将 i 的值放入对象的某个属性中
Integer ii = Integer.valueOf(i);
Integer ij = new Integer(i);

// 拆箱操作,将 Integer 对象中的值取出,放到一个基本数据类型中
int j = ii.intValue();

 1.2 Automatic boxing and automatic unboxing

It can be seen that during use, boxing and unboxing bring a lot of code, so in order to reduce the burden on developers, Java provides an automatic mechanism.

int i = 10;

Integer ii = i; // 自动装箱
Integer ij = (Integer)i; // 自动装箱

int j = ii; // 自动拆箱
int k = (int)ii; // 自动拆箱

 [Interview question]
What does the following code output and why?

public static void main(String[] args) {
    Integer a = 100;
    Integer b = 100;

    Integer c = 128;
    Integer d = 128;

    System.out.println(a == b); //true
    System.out.println(c == d); //false
}

The only operation that occurs in the whole process is boxing, and the boxing operation calls the valueOf method. Let’s take a look at the valueOf method.

We can see that there is a parameter herei. If this parameter is in if is not in this range, a new object is created. means cache. We can think of it as a cache array. If cache Within the specified range, an array is returned.

Then we can make a preliminary guess: Our boxing operation is actually performed in an array. This array has certain limits. When we take elements with the same subscript in this array, then the returned The values ​​are the same. If we take elements outside this array, the values ​​we get may be different. So now there is a question:Where is the limit of this array?

In other words, the value of thislow is-128, let’s click low

We can clearly see thatlow has a value of -128, while the value of high is 127, and there are between -128 and 127 256 numbers, that is to say, if this i falls within the 256 range, it will be placed in the cache Inside the array,

So how did he save it into this array?

 We use the boundary value to calculate, first use -128 to calculate

So the index stored at 0 is -128 

Let’s use 127 to calculate 

 So this array stores -128 under 0 and 127 under 255. We are counting 100

 So the number 100 is obtained by subscripting 228

Let's look back at this code

public static void main(String[] args) {
    Integer a = 100;
    Integer b = 100;

    Integer c = 128;
    Integer d = 128;

    System.out.println(a == b); //true
    System.out.println(c == d); //false
}

Summary: Every time the a/b boxing operation takes data, it gets the 100 within the 228 subscript. In this case, the value is the same. If we take the value as 128, will it exceed this range? If it exceeds the range, create a new object, and the data obtained will be different.

 

 2. What are generics

         General classes and methods can only use specific types: either basic types or custom classes. If you want to write code that can be applied to multiple types, this rigid restriction will be very restrictive to the code.

                                                                                                      

        Generics are a new syntax introduced in JDK1.5. In layman’s terms, generics: is suitable for many, many types . From a code perspective, the type is parameterized.

 3. Export generics

 Implement a class that contains an array member so that any type of data can be stored in the array, and the value of a certain subscript in the array can also be returned according to the member method?

Idea:
1. The array we have learned before can only store elements of specified types,

For example: int[] array = new int[10];

          String[] strs = new String[10];


2. The parent class of all classes, the default is the Object class. Can an array be created as an Object?
    Code example:

class MyArray {
    public Object[] array = new Object[10];
    public Object getPos(int pos) {
        return this.array[pos];
    }
    public void setVal(int pos,Object val) {
        this.array[pos] = val;
    }
}

public class TestDemo {
    public static void main(String[] args) {
        MyArray myArray = new MyArray();
        myArray.setVal(0,10);
        myArray.setVal(1,"hello");//字符串也可以存放
        String ret = myArray.getPos(1);//编译报错
        System.out.println(ret);
    }
}

Problem: After implementing the above code, we found that
1. Any type of data can be stored
2. The subscript No. 1 itself is a string, but Correct compilation error. Forced type conversion is required
Although in this case, any data in the current array can be stored, but in more cases, we still hope that it can only hold one data type. Instead of holding so many types at the same time. So, the main purpose of generics is to specify what type of object the current container should hold. Let the compiler do the checking. At this point, you need to pass the type as a parameter. Just pass in whatever type you need.

3.1 Grammar 

class 泛型类名称<类型形参列表> {
    // 这里可以使用类型参数
}

class ClassName<T1, T2, ..., Tn> {
}

class 泛型类名称<类型形参列表> extends 继承类/* 这里可以使用类型参数 */ {
    // 这里可以使用类型参数
}

class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
    // 可以只使用部分类型参数
}

 The above code is rewritten as follows:

class MyArray<T> {
    public T[] array = (T[])new Object[10];//1
    public T getPos(int pos) {
        return this.array[pos];
    }
    public void setVal(int pos,T val) {
        this.array[pos] = val;
    }
}
public class TestDemo {
    public static void main(String[] args) {
        MyArray<Integer> myArray = new MyArray<>();//2
        myArray.setVal(0,10);
        myArray.setVal(1,12);
        int ret = myArray.getPos(1);//3
        System.out.println(ret);
        myArray.setVal(2,"bit");//4
    }
}

 Code explanation:
1. The <T> after the class name represents a placeholder, indicating that the current class is a generic class
Understand : [Specification] Type parameters are generally represented by a capital letter. Commonly used names are:
        E represents Element
        K Represents Key
        V represents Value
        N represents Number
        T represents Type
        S, U , V etc. - second, third, fourth type

2. Note 1, arrays of generic types cannot be new, which means:

T[] ts = new T[5];//是不对的

3. In comment 2, add<Integer> specify the current type
4. At comment 3, no forced type conversion is required
5. At comment 4, the code compiles and an error is reported. At this time, because the current type of the class is specified at comment 2, at this time at comment 4, the compiler The container will help us perform type checking when storing elements.

4 Use of generic classes

4.1 Grammar 

Generic class<type argument> variable name; //Define a generic class reference
new generic class<type argument>(constructor actual Parameter); // Instantiate a generic class object 

4.2 Example 

MyArray<Integer> list = new MyArray<Integer>();

Note: Generics can only accept classes, and all basic data types must use wrapper classes!

4.3 Type Inference 

 When the compiler can deduce the type arguments from the context, filling in the type arguments can be omitted.

MyArray<Integer> list = new MyArray<>(); // It can be deduced that the type actual parameter required for instantiation is Integer 

 5. Raw Type (understand)

5.1 Description

A naked type is a generic class but does not have type parameters. For example, MyArrayList is a naked type.

MyArray list = new MyArray();

Note: We should not use naked types ourselves. Naked types are mechanisms reserved for compatibility with older versions of APIs
In the type erasure part below, we will also talk about the compiler. How to use naked types.
 Summary:
1. Generics parameterize the data type and transfer it
2. Use <T> The current class is a generic class.
3. Advantages of generics so far: data type parameterization, automatic type checking and conversion at compile time

 

6 How are generics compiled?

 6.1 Erase mechanism

So, how are generics compiled? This question was also an interview question before. Generics are inherently a very difficult syntax, and it still takes a certain amount of time to polish it to understand it well. During the compilation process, the mechanism of replacing all T with Object is called: erasure mechanism.
Java's generic mechanism is implemented at the compilation level. The bytecode generated by the compiler does not contain generic type information during runtime.
An introduction to the article about the generic erasure mechanism: https://zhuanlan.zhihu.com/p/51452375

 Ask questions: 1. So why, t [] ts = new t [5]; []ts = new Object[5]? 2. Type erasure, does it have to turn T into Object?

1. T[] ts = new T[5]; is wrong, because in Java, generic types will be during compilationErased, unable to create a generic array. The compiler will erase T[] ts = new T[5] to Object[] ts = new Object[5], but this is not exactly equivalentIn Object[] ts = new Object[5]. Because generics have the characteristics of type erasure, when T is erased as Object, it is just an ordinary Object type and cannot implement the restrictions and constraints of generics. Therefore, if you use T[] ts = new T[5]; to create an array, when you need to assign elements in the array to variables of type T, a ClassCastException may be thrown. Exception.

2. Type erasure does not necessarily change T into Object. The generic type parameter T will be replaced by its upper limit type (if T does not specify an upper limit, it will be Object). For example, if you define a generic class:

```
public class MyClass<T extends Number> {
    //...
}
```

At compile time, type erasure replaces T with Number. Therefore, MyClass<String> will be replaced by MyClass<Number> after compilation. When instantiating a MyClass object, if a non-Number type is used as an actual type parameter, the compiler will report an error. Therefore, generics can effectively constrain the scope of type parameters at compile time, improving code safety and readability.

 6.2 Why cannot instantiate a generic type array

Code 1:

class MyArray<T> {
    public T[] array = (T[])new Object[10];

    public T getPos(int pos) {
        return this.array[pos];
    }

    public void setVal(int pos,T val) {
        this.array[pos] = val;
    }

    public T[] getArray() {
        return array;
    }
}

public static void main(String[] args) {
    MyArray<Integer> myArray1 = new MyArray<>();
    Integer[] strings = myArray1.getArray();
}


/*
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
at TestDemo.main(TestDemo.java:31)
*/

 Reason: The replaced method is: assign Object[] to Integer[] reference, and the program reports an error.

public Object[] getArray() {
    return array;
}

 In layman's terms: the returned Object array may store any data type, it may be String, it may be Person. When running, it will be directly transferred to an array of Integer type. The compiler considers it unsafe.

 

7 Upper bound for generics

When defining a generic class, sometimes it is necessary to impose certain constraints on the type variables passed in, which can be restricted through type boundaries.​ 

7.1 Syntax

class generic class name<type parameter extends type boundary> { ...

7.2 Example 

public class MyArray<E extends Number> {
...

Accepts only subtypes of Number as type arguments of E

MyArray<Integer> l1; // Normal, because Integer is a subtype of Number
MyArray<String> l2; // Compilation error, because String is not a subtype of Number< /span>

error: type argument String is not within bounds of type-variable E
MyArrayList<String> l2;
^
where E is a type-variable:
E extends Number declared in class MyArrayList 

Understanding: No type boundary E is specified, which can be regarded as E extends Object

7.3 Complex examples

public class MyArray<E extends Comparable<E>> {
...

E must implement the Comparable interface 

8 Generic methods 

 8.1 Definition syntax

Method qualifier <type parameter list> return value type method name (parameter list) { ... } 

8.2 Example 

public class Util {
    //静态的泛型方法 需要在static后用<>声明泛型类型参数
    public static <E> void swap(E[] array, int i, int j) {
        E t = array[i];
        array[i] = array[j];
        array[j] = t;
    }
}

 8.3 Usage examples - type deduction is possible

Integer[] a = { ... };
swap(a, 0, 9);

String[] b = { ... };
swap(b, 0, 9);

 8.4 Usage example - no type deduction

Integer[] a = { ... };
Util.<Integer>swap(a, 0, 9);

String[] b = { ... };
Util.<String>swap(b, 0, 9);

 

(Note: The picture comes from the Internet. If there is any infringement, please contact us to delete it)  

Hope this helps everyone, thanks for watching! ! !

Guess you like

Origin blog.csdn.net/A1546553960/article/details/134764875