Java의 Generics는 코드 재사용성과 유형 안전성을 가능하게 하는 고급 기능입니다. 코드 재사용 기능은 일반 클래스, 인터페이스, 생성자 및 메서드를 정의하여 달성됩니다. Generics는 데이터 유형 선언을 사용하여 유형 안전성을 보장함으로써 런타임 오류 가능성을 제거합니다. 꺾쇠 괄호 '
무료 소프트웨어 개발 과정 시작
웹 개발, 프로그래밍 언어, 소프트웨어 테스팅 등
일반 사항은 꺾쇠 괄호 "<>"를 사용하여 구현됩니다. 괄호 안에는 유형 매개변수 "T"가 포함되어 있습니다. 예를 들어,
일반 클래스는 다음과 같이 정의할 수 있습니다.
코드:
public class MyGenericClass<T> {…}
표준 유형 매개변수는 다음과 같습니다.
다중 매개변수의 경우 S, U, V 등을 사용하여 각각 두 번째, 세 번째, 네 번째 매개변수를 정의합니다.
형식 안전이란 무엇이며 어떻게 작동하나요? 일반 클래스, 인터페이스, 생성자 및 메서드는 재사용이 가능한 일반 클래스 및 메서드와 어떻게 다릅니까?
정적 유형 언어인 Java는 사용하기 전에 변수의 데이터 유형을 선언해야 합니다.
예:
코드:
String myString ="eduCBA";
위 코드에서 "String"은 데이터 유형이고 "myString"은 유형이 String인 값을 보유할 변수입니다.
이제 아래와 같이 문자열 대신 부울 값을 전달하려고 하면 다음과 같습니다.
코드:
String myBooleanStr = true;
즉시 "유형 불일치: 부울에서 문자열로 변환할 수 없습니다"라는 컴파일 시간 오류가 발생합니다.
출력:
이제 일반 메소드를 정의해 보겠습니다.
코드:
public static void welcome(String name){ System.out.println("welcome to " + name); }
이 메소드는 문자열 매개변수를 전달해야만 호출할 수 있습니다.
코드:
welcome("eduCBA");
“welcome to eduCBA”가 출력됩니다
그러나 문자열만 이 메서드를 호출할 수 있습니다. 정수 또는 부울과 같은 다른 데이터 유형을 전달하려고 하면 "Runner 유형의 Welcome(String) 메서드는 인수(boolean)에 적용할 수 없습니다."라는 컴파일 시간 오류가 발생합니다.
출력:
다른 데이터 유형에 대해 유사한 메소드를 호출하려는 경우 필수 데이터 유형을 매개변수로 허용하는 새 메소드를 생성할 수 있습니다. 다양한 데이터 유형의 매개변수로 메소드를 다시 작성하는 기술을 "메서드 오버로딩"이라고 합니다. 그러나 이 접근 방식의 한 가지 단점은 코드 크기가 더 커질 수 있다는 것입니다.
Generics를 사용하여 위의 방법을 다시 작성하고 필요한 모든 데이터 유형에 사용할 수도 있습니다.
일반 메소드 정의:
코드:
public static <T> void welcome(T t){ System.out.println("it is " + t); }
참고: 여기서 "t"는 T 유형의 객체입니다. 메소드를 호출하는 데 사용되는 실제 데이터 유형은 유형 매개변수 "T"에 할당됩니다.
이를 통해 문자열, 부울, 정수 등을 포함하여 필요에 따라 다양한 데이터 유형으로 메소드를 재사용할 수 있습니다.
코드:
welcome("educba"); Integer myint = 1; welcome(myint); welcome(true);
위 명령문은 아래 출력을 제공합니다.
출력:
it is educba it is 1 it is true
따라서 여기서 Generics를 사용하면 다양한 데이터 유형에 대해 방법을 재사용할 수 있습니다.
배열과 컬렉션의 주요 차이점 중 하나는 배열은 동종 데이터만 저장할 수 있는 반면 컬렉션은 이기종 데이터를 저장할 수 있다는 것입니다. 즉, 컬렉션은 사용자 정의 데이터 유형을 포함하여 모든 유형의 객체를 저장할 수 있습니다.
참고: 컬렉션은 기본 데이터 유형이 아닌 사용자 정의 데이터 유형을 포함한 객체만 보유할 수 있습니다. 기본 데이터 유형으로 작업하기 위해 컬렉션은 래퍼 클래스를 사용합니다.
Now, let’s consider an ArrayList.
Code:
ArrayList myList = new ArrayList();
One can add elements of various data types, such as strings, integers, and doubles, to an ArrayList object.
Code:
myList.add("eduCBA"); myList.add(1); myList.add(5.2);
On printing the ArrayList object, one can see that it contains the following values: [eduCBA, 1, 5.2].
Output:
To retrieve these values into variables, one needs to typecast them.
Code:
String someStr = (String)myList.get(0); Integer someInt = (Integer)myList.get(1); Double someFlt = (Double)myList.get(2);
If one does not typecast, it will prompt a compile-time error stating, “Type mismatch: cannot convert from Object to String”
Output:
Thus, one must typecast them to their respective types while retrieving the objects from the ArrayList. However, in real-time scenarios, an ArrayList can contain thousands of records, and manually typecasting every object may not be feasible. There is the risk of mistakenly typecasting an object to an incorrect data type. In such cases, a runtime error will occur, stating “Exception in thread “main” java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at com.serviceClasess.Runner.main(Runner.java:43)”.
As there is no guarantee with regard to the type of data present inside a collection (in this case, ArrayList), they are considered unsafe to use with respect to type. Here, Generics play a role in providing type safety.
Code:
ArrayList<String> myList = new ArrayList<String>();
The String type is specified inside the angular brackets “>” which means that this particular implementation of ArrayList can only hold String type data. If one tries to add another data type, it will simply throw a compile-time error. Here, the ArrayList has been made type-safe by eliminating its chances of adding a data type other than “String.”
Output:
Now, since one has specified the data type that is allowed to be added to the collection with the help of Generics, there is no need to typecast it while retrieving the data. One can simply retrieve the data by writing.
Code:
String someStr = myList.get(0);
Output:
So far, we have seen how we can achieve type safety and code reusability with Generics.
In addition to type safety and code reusability, here are some other features that Generics can provide:
In the case of a bounded type, the data type of a parameter is bounded to a particular range. The keyword “extends” helps achieve this.
For example, let’s consider a Generic class with a bounded type parameter that extends the ‘Runnable interface’:
Code:
class myGenericClass<T extends Runnable>{}
Now, while creating its object in another class:
Code:
myGenericClass<Thread> myGen = new myGenericClass<Thread>();
The above statement will execute perfectly without any errors. In the case of the bounded type, one can pass the same class type or its child class type. Also, one can bind the parameter type to an interface and pass its implementations when invoking it, as in the example above.
What happens if one uses any other type of parameter?
Code:
myGenericClass<Integer> myGen = new myGenericClass<Integer >();
In the above case, it will result in a compile-time error, stating “Bound mismatch: The type Integer is not a valid substitute for the typecast
Output:
Example:
Code:
class myGeneric<T extends Number & Runnable>{}
In this case, one can pass any type that extends the Number class and implements the Runnable interface. However, when using multiple bounded types, a few things should be noted:
The “?” (question mark) symbol represents Type Wildcards. It makes use of two main keywords:
Example:
Code:
ArrayList<? extends T> al
The ArrayList object “al” will hold any data of type T and all its subclasses.
Code:
ArrayList<? super T> al
The ArrayList object “al” will hold any data of type T and all its superclasses.
Generics scope is limited to compile time, i.e., the Generics concept is applicable only at compile time but not at run time.
Example:
Code:
ArrayList myList = new ArrayList<Integer>(); ArrayList myList = new ArrayList<Float>(); ArrayList myList = new ArrayList<Double>(); ArrayList myList = new ArrayList<Boolean>();
Here all the above four statements are the same. They will allow adding any type of data to the list object.
Generics renders coding easy for a coder. It diminishes the chances of encountering ClassCastException at run time by providing strong type-checking. Also, it eliminates the need for typecasting, which means less code needs to be written. It allows the development of Generic algorithms independent of the data type they are working with.
위 내용은 Java의 제네릭이란 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!