ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자바 기본 정리 - <JAVA 프로그래밍 면접 이렇게 준비한다>
    자바/Java 공부 2018. 12. 27. 14:32




    프롤로그

    <JAVA 프로그래밍 면접 이렇게 준비한다>를 읽으면서 자바 기본 개념을 공부하고 있습니다. 웹 개발자가 되기 위해서 공부해야 하는 것들이 잘 정리된 책이라고 생각합니다.

    이 책만으로는 깊이있는 공부는 어렵습니다. 다만 중요한 개념들이 요약, 정리되어 있어서 이 책을 참고로 공부 방향을 잡고 좀 더 깊이 있는 공부를 할 수 있다고 생각합니다. 

    공부를 어떻게해야 할지 고민이었는데 이 책이 많은 도움이 되었습니다.

      

    8장-자바 기본을 읽으면서 내용을 정리하고 이해가 안되는 부분은 추가로 공부하여 작성하고 있습니다. 






    원시 타입(Primitive type)

    기본 타입(원시 타입)의 종류 char, byte, short, int , long, float, double, boolean 등 8개이다.

    원시 타입은 항상 값이 있는 상태다. 참조 타입(객체)처럼 null이 될 수 없다. (int는 0, boolean은 false, float은 0.0f가 기본 값)

    숫자를 값으로 입력할때는 컴파일러가 int와 long, float과 double을 구분하도록 리터럴에 L, F를 붙여준다. int와 double은 기본 값으로 생략 가능하다. (리터럴=상수)


    long a = 10L;

    float b = 3.6f;


    저장 범위가 좁은 타입의 값을 넓은 타입의 값으로 저장 할 수 있다. 예를 들어 int(4byte) -> long(8byte) 

    반대는 컴파일 에러가 발생한다. 명시적 형변환으로 대입 할 수는 있지만 오버플로우가 발생한다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package study.type;
     
    public class OverFlow {
        
        Integer number = Integer.MAX_VALUE;
        static long overInt = (long)(Integer.MAX_VALUE)+1;
        
        public static void main(String[] args) {
            //overflow
            int overflow = (int)overInt; //명시적 형변환(long -> int)
            System.out.println(overflow); //int 저장범위 초과로 -2147483648 출력
        }
    }
     
    cs




    객체란(Object)?

    기능이나 속성이 정의된 클래스가 메모리에 생성된 상태이다.

    원시 타입을 제외한 모든 변수는 참조 타입, 즉 객체이다.

    동일한 객체를 가리키는 참조변수는 여러개 존재 할 수 있다. 

    그 중 하나의 인스턴스에 변경이 생기면 다른 인스턴스에 영향을 준다.


    객체 생성 과정

    1. 참조 변수 선언(declaring reference variable)

    Car car1;

    오직 참조 변수의 메모리만 할당되고 객체는 null 상태이다. (기본 값이 null)



    2. 객체 초기화(Initializing an Object)

    Car car1 = new Car();

    new 연산자와 클래스 생성자에 의한 객체 초기화시 메모리가 할당되고 그 위치에 클래스의 인스턴스가 생성된다. 

    참조 변수에 생성된 인스턴스의 메모리 주소가 저장된다.




    참고자료:

    객체,오브젝트,클래스에 대한 설명





    hashcode()와 equals()

    java.lang.Object 클래스가 제공하는 메서드이고 오브젝트를 비교할때 쓰인다.

    그런데 왜 오브젝트를 비교하는데 2개에 메서드가 필요할까?

    자바 오브젝트는 hash-based data structure로 저장되면서 해쉬코드가 부여된다. 해쉬코드는 자료 구조 안에 있는 오브젝트에 빠른 접근을 위해서 사용된다. 중요한 점은 똑같은 해쉬코드를 가진 오브젝트가 하나 이상 있을 수 있다는 점이다. 

    그러므로 두 메서드를 다룰때 아래의 조건을 고려해야 한다.


    A.equals(B)가 true인 오브젝트 A와 B는 똑같은 해쉬코드를 같는다. O

    equals() 리턴 값이 false인 경우, 해쉬코드도 무조건 다르다. X

    해쉬코드가 같은 오브젝트는 equals() true를 리턴한다. X



    참고자료:




    final 키워드는 객체 참조에 어떤 영향을 주나?

    원시 타입과 동일하게 객체 참조 변수에 할당된 메모리 위치가 변경될 수 없다. 하지만 참조변수 객체의 내부 속성은 final 키워드가 없을 경우 변경될 수 있다


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package study.Final;
     
    final class FinalClass {
        String exam = "a";
        final String exam2 = "b";
    }
     
    public class FinalMain {
        public static void main(String[] args) {
            final FinalClass ft = new FinalClass();
             ft = new FinalClass(); //The final local variable ft cannot be assigned. 
            ft.exam = "c"; //변경 가능
            ft.exam2 = "d"//The final field FinalTest.exam2 cannot be assigned
        }
    }
    cs





    가시성 수정자(visibility modifier) 또는 접근 제한자

    private - 오직 클래스 내에서만 사용 가능하다. 하위 클래스에서 접근 불가능 하지만

    같은 클래스 타입의 서로 다른 인스턴스에서는 접근 가능하다. 

    protected - 하위 클래스에서 접근 가능

    public - 어디서든 접근 가능

    none - 패키지 내에서만 접근가능





    static 키워드의 역할

    클래스 내부에 정의되는 정적 변수와 메서드는 단일 인스턴스에는 속하지 않는다. 모든 인스턴스에서 공통으로 사용하는 속성이다.

    인스턴스 이름 보다는 클래스 이름에 .연산자로 접근하는게 바람직하다. 


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package study.Static;
     
    public class StaticCheck {
        static String a = "thisIsStatic";
        String b = "variable";
        
        public static void main(String[] args) {
            System.out.println(StaticCheck.a); //static 변수 바로 접근
            System.out.println(StaticCheck.b); //Cannot make a static reference to the non-static field
      StaticCheck.b
        }
    }

    cs




    다형성과 상속

    상속:

    부모클래스의 속성과 기능을 자식 클래스가 그대로 사용할 수 있게 해준다. 반면에 부모 클래스는 자식 클래스의 속성과 기능을 사용할 수 없다. 

    서로 상속 관계에 있는 클래스들은 다형성을 띈다. 묵시적 형변환과 명시적 형변환.


    다형성:

    자식 클래스는 상속 받고 있는 부모 클래스의 타입으로 정의될 수 있고(묵시적 형변환) 부모 클래스의 속성과 기능 역시 사용할 수 있다. 반대로 부모 타입의 객체가 자식 객체의 타입을 사용하려면 명시적 형변환이 필요하다. 그리고 자식 클래스의 속성과 기능은 사용할 수 없다.






    String 객체의 값을 변경 할 수 있나?

    없다. String 객체를 다루는 substring, split 같은 메서드는 기존 객체를 변경하는게 아니라 새로운 String 객체의 복사본을 반환한다.

    이렇게 불변성을 띄는 클래스는 Integer, Double Character, BigIntger 등이 있다. 동시 스레드에서 사용이 자유롭다.






    인터닝

    String 객체는 변경 되지 않고 새롭게 생성된 객체에 변경된 값이 저장된다. 별도의 관리가 없다면 중복을 포함한 수 많은 String 객체가 생성되어 많은 heap 메모리를 차지할 것이다. 

    인터닝은 JVM이 클래스를 로딩하면서 모든 리터럴을 constant pool에 위치시키고 이후 중복으로 반복해서 사용되는 String 리터럴은 하나의 같은 상수(constant)를 참조하게 되는 것을 말한다.


    Constant pool은 위치는 java 7부터 PermGen에서 heap 메모리로 이동되었다. 참조되지 않는 String 리터럴은 가비지콜렉터의 관리를 받는다. (java6에서는 사이즈가 작고 고정되어 있는 PermGen 메모리에 있었고 OutOfMemoryException 위험이 있었다.)




    참고자료: 

    >수 풀의 위치와 가비지 콜렉터





    제네릭(Generic)

    제네릭은 컬렉션 클래스에 저장되는 자료의 타입을 컴파일러가 특정할 수 있게 한다. 예를 들어 제너릭이 없는 List 인스턴스에는 모든 타입에 객체가 저장 될 수 있다. 저장된 객체를 사용하기 위해서 get 메서드로 가져올때 반환 타입은 Object이다. 이를 다시 String으로 형변환하는 과정에서 객체가 다른 타입일 경우 ClassCastException이 발생할 수 있다.

    제네릭은 컬렉션에 객체를 저장할때와 꺼내올때 타입을 특정해주므로 프로그램 실행 단계에서 발생할 수 있는 에러를 컴파일 단계에서 미리 예방해준다. 


    1
    2
    3
    4
    5
    6
    7
        List list1 = new ArrayList();
            list1.add("string");
            list1.add(11);
            
            System.out.println("1:"+list1.size());
            System.out.println(list1.get(0));
            //System.out.println((String)list1.get(1)); //실행 중 형변환 과정에서 익셉션 에러 발생 
    cs







    오토박싱과 언박싱
    오토박싱
    자바5에서 처음 도입 되었다. 컴파일러 원시 타입(primitive type)을 참조 타입으로 자동 변경 하는 것이다. (int -> Integer, boolean -> Boolean)

    언박싱
    위와는 반대로 컴파일러가 참조 타입을 원시 타입으로 변경하는 것이다. 주의 할점은 참조 타입은 null 값을 가질 수 있지만 원시 타입은 그렇지 않다는 점이다. 예를 들어 Integer 타입을 int로 변경할때, Integer 타입의 값이 null 이라면 NullPointerException 예외가 발생한다.

    제너릭에 원시타입(primitive type)을 사용할 수 없는 이유
    제너릭은 이전 버전의 자바 JVM과의 호환성을 위해서 컴파일 타임(단계?)에서 제거 된다. 그리고 제너릭 타입은 Object 타입으로 캐스팅 된다. 하지만 원시 타입은 Object 타입으로 캐스팅 될 수 없다.




    예외(Exception)
    Error와 Exception은 다르다. 
    Error는 자바 실행 환경(JRE)과 관련된 것으로 프로그래머의 책임이 아니다. (ex. OutOfMemoryError)
    Exception은 프로그램 실행 중 발생하는 것으로 프로그래머의 책임이다. (ex. NullPointerException)


    예외(Exception) 처리 과정
    1. 어떤 메서드에서 예외가 발생하면 해당 메서드가 exception 객체를 생성해서 JVM에 전달한다.(=Throwing an Exception)
    2. JVM은 Exception Handler를 포함한 메서드를 CallStack 안에서 찾는다. 
    3. exception 타입을 다룰 수 있는 핸들러를 찾으면 exception 객체를 전달한다. 만약 찾지 못하면 프로그램 종료와 함께 Default Exception Handler를 사용한다.


    Checked, Unchecked Exception
    Checked 
    컴파일 시 확인되는 예외, 메서드 내에 Checked Exception이 발생할 수 있는 코드가 있을 경우, throw 키워드를 이용해서
    예외를 특정하거나 try-catch block으로 처리해야 한다.

    예외를 특정해줘서 코드에 잘못된 부분을 금방 알 수 있게 해주고 해당 메서드가 어떻게 동작하는지 이해하기 쉽게 해준다. 하지만 try-catch block 사용으로 코드양이 많아지고 나중에 유지보수가 어려울 수 있다.

    UnChecked 
    컴파일 시 확인되지 않는 예외, 컴파일 시에는 이상이 없지만 프로그램 실행시 exception이 발생한다. 모두 RuntimeException의 하위 클래스이다. 런타임 예외는 프로그래머가 미리 방지해야 하는 예외다.


    Chained Exception
    어떤 예외가 발생한 원인이 또 다른 예외인 경우, 연쇄 예외를 사용하면 예외가 처음 발생한 원인을 로그에서 쉽게 알아볼 수 있다. 



    참고자료: