자바 제네릭이 필요한 이유, 사용법, 개념을 문제위주로 정리했습니다.
______
에 어떤 것이 들어와야 하는지 작성class Sample {
private _________ a;
Sample( __________ x ) {
this.a = x;
}
public __________ getA() {
return a;
}
}
public class collection_Generic1 {
public static void main(String[] args) {
Sample s1 = new Sample("안녕하세요~");
System.out.println( s1.getA() );
Sample s2 = new Sample(100);
System.out.println( s2.getA() );
class Sample{
//Field
private Object obj;
//Constructor
Sample(Object x){
this.obj= x;
}
//Method
public Object getObj(){
return obj;
}
//정보 출력
void printInfo(){
System.out.println(obj.getClass().getName()); // 객체가 속하는 클래스의 정보를 출력하는 메서드
}
}
public class Generic1 {
public static void main(String[] args) {
// [1] : 객체 생성 --> 문자열
Sample s1 = new Sample("안녕하세요");
System.out.println(s1.getObj());
s1.printInfo();
System.out.println("------------------------------------------");
// [2] : 객체 생성 --> 숫자
Sample s2 = new Sample(100); // ERR (클래스의 타입이 int, String 일 경우) -->
// 타입을 Object 로 바꿔주면 해결됨. --> Object 타입으로 지정시, 어떤 객체를 생성하고 불러도 다 가능함
System.out.println(s2.getObj());
s2.printInfo();
System.out.println("------------------------------------------");
}
}
// [3] : 객체 생성 --> Object
Sample s3 = new Sample(new Object()); // 오브젝트 객체를 생성해서 샘플 객체에 보내는 것이 됨
// --> (로직)1. 생성자에서 받아서 호출됨, 타입이 오브젝트이니까 모든 타입을 받아줌. --> 오브젝트로 넘겨주니까 오브젝트로 받는 것은 당연.
System.out.println(s3.getObj()); //객체니까 객체 주소값 출력함
s3.printInfo(); // 객체의 정보 출력됨
// [4] : 위와같이 사용시 --> 단점 존재
// s1 --> 문자열
s1.getObj(); // 이 메서드를 호출하면, (메서드 안에서) return 해주니까 뭔가를 반환하는 중임. --> obj 에 있는 값을 그대로 리턴해줌
// --> 메서드 타입은 오브젝트 --> (이말은) 리턴되는 반환타입이 오브젝트임.
// --> (Constructor)생성자가 받을 때엔 좋았는데, 이것을 통해서 (Method)에서 내보낼 땐 반환타입이 오브젝트라서, 상관이 생김.
// --> 그때그때 사용할 때마다, 형변환을 해주어야합니다. string 사용시 (string)으로
Object str = s1.getObj(); // 리턴시 반환 타입이 Object입니다.
System.out.println(str); // 정상코드,("안녕하세요")
System.out.print(str.length()); // ERR, (문자열의 길이를 알아보려니까)
String str = (String)s1.getObj; //이렇게 형변환으로 사용해야 하는 이유가,
// 문자열의 길이 및 String 클래스가 가진 유용한 여러 메서드를 사용하기 위해서 형변환함.
System.out.print(str.length()); // 6, 정상작동 코드
/*
// case 1, (문자)
String str = s1.getObj(); // ERR . 리턴시 반환 타입이 Object 임.
//-- > 즉, Object 로 반환되다 보니까, ERR 나지 않게 하려면, 형변환을 통해서 사용해야합니다.
String str = (String)s1.getObj(); // 정상작동하는 코드
// case 2, 숫자(정수)
int num = s2.getObj(); //ERR
int num = (int)s2.getObj(); // 됨. -- > 사용할 때마다 형변환을 해줘야함. --> 번거로움
*/
// 둘 중 하나로 수정
// 1) int num = (int)s2.getObj();
Object num = s2.getObj();
// s2 --> 숫자
System.out.print(num+100); // 이렇게 하게 된다면 ? --> ERR.
// --> 오브젝트기 때문에, 직접적인 연산 안됨. -- > 형변환 해줘야함
System.out.print((int)num+100); // 이렇게 형변환해줘야함
int num = (int)s2.getObj(); // 이렇게 형변환 해주면 무상관.
System.out.print(num+100); // 200, 계산가능해짐. 위에 형변환해줘서
class Person{
public Object obj;
Person( Object obj) {
this,obj = obj;
}
}
class Student{
public int grade;
Student(int grade) {
this.grade = grade;
}
}
public class GenericTest{
public void main(String[]args){
----------------------------------------
----------------------------------------
}
}
필자는, (컴파일 되고)잘 수행되지만 에러가 발생하지 않는경우 상당히
안좋은코드입니다.
따라서, 컴파일러 단계에서 에러가 발생해야 상당히 좋은 코드라고 생각합니다.
--> 제네릭이 필요한 이유
class Person {
//Field
public Object obj;
//Constructor
Person (Student obj){
this.obj = obj; // 파라미터로 넘어오는 obj 를 obj 로 할당
}
}
class Student{
//Field
public int grade;
//Constructor
Student(int grade){
this.grade = grade;
}
}
class Teacher{
}
public class Generic2 {
public static void main(String[] args) {
// [1] : 객체생성
Person p1 = new Person(new Student(3)); // 참조형 객체 생성 --> Person 생성자에 어떤 값을
// 보내주더라도 object 라서 다 받아줄 수 있음
System.out.println(p1.obj);
// Person p2 = new Person(new Teacher()); // ERR.--> Person 생성자의
// 매개변수의 타입을 Student 로 지정해서, 학생 객체만 받을 수 있게 해둬서
// 매개변수 타입이 Object 라면, Err 해결할 수 있음.
/*
[2] : 객체생성
Person p3 = new Person(new Student(1));
Student s1 = (Student) p1.obj; // 이렇게 형변환을 해서 사용해야함. 아니면 ERR.
String str = (String) p1.obj;
즉, 사용할 때엔 그에 맞는 형변환이 필요함.
System.out.println(str.length()); // 6
*/
// [3] : 형변환 ->cast
Teacher t1 = (Teacher)p1.obj; // 이 부분은 컴파일 단게에서는 에러가 안나고,
// 컴파일이 잘됨. --> 실행하는 단계에서 ClassCast 오류가 발생합니다.
}
}
// [1] : 객체 생성 --> String
Sample_______________ s1 = new Sample _______________( "안녕" );
// [2] : 객체 생성 --> Integer
Sample _______________ s2 = new Sample _______________(10);
import java.lang.*;
class Sample<T> { // 이게 키포인트. Integer, String 등, 어떤 타입으로 올 지 모르니까 포괄적인 T 타입(제네릭)을 사용해줌.
//Field
private T obj; // 아무 문자나 쓰는데, 대문자 'T' (Type)를 씀
//Constructor
Sample(T x) { //포괄적인 타입을 받아주겠다는 소리
this.obj= x;
}
//Method
T getObj(){ // 제네릭 타입의 T 로 반환,
return obj;
}
void printInfo(){
System.out.println(obj.getClass().getName());
}
}
public class Generic3 {
public static void main(String[] args) {
// [1] : 객체 생성 --> String
Sample<String> s1 = new Sample<String>( "안녕하세요~" ); // <타입명>, 타입명은 다양한 타입으로 바뀔 수 있음. -->
// 즉, 다양한 제네릭 타입으로 바뀔 수 있음. --> 즉, 받는 쪽에서, 샘플클래스를 통해 객체를 만들 떄,
// 다양한 타입이 만들(넘어올) 수 있겠구나를 생각해내야함. --> 다양한 타입으로 객체생성 될 수 있음 -->클래스 옆에 <T>붙임
// <결론> 다양한 타입이 적혀질 수 있음(메인부분에)
// --> (샘플클래스 부분에) 다양한 타입을 받을 수 있게 `<T>`, (필드,생성자,메서드)의 타입도 'T'
System.out.println(s1.getObj());
s1.printInfo();
System.out.println("------------------------------------------------");
// [2] 객체생성 --> Integer
Sample<Integer> s2 = new Sample<Integer>(100);
System.out.println(s2.getObj());
s2.printInfo();
System.out.println("------------------------------------------------");
// [3] 형변환 없이 사용해보기
String str = s1.getObj(); // 객체를 생성할 때, String 타입으로 되어있어서 가능함.
// --> 앞에서는 Object 타입이라서 `String str =(String)s1.getObj();` 을 해줬어야함. BUT, 지금은 형변환 필요x
System.out.println(str.length()); // 6
// 즉, 제네릭을 사용하면 형변환을 고민할 필요없음. 형변환 없이 바로 사용가능.
System.out.println(s1.getObj().length()); // 6
System.out.print(s2.getObj()+100); // 200
}
}