본문 바로가기

자바

[자바기초요약7] 기타제어자( static, final, abstract )

# 기타제어자 - static  final   abstract      (접근제어자 public protected default private)
 

# static    static붙힌것과 주소만들어주는것( A o=new A() )은 메모리에 올라감
             static이 붙으면 오버라이딩 안됨( static은 고정된, 정적인 이라는 뜻 )
 의미 : 클래스에 속한것이라는 의미를 가진다.
 위치 : 멤버변수앞, 메서드앞
 
멤버변수앞에 선언되는 static : 객체간에 어떤 변수를 공유하고자할때
    (static이 메서드앞에 선언될 때 : 편하게 사용하자..)
 
[ex]
class A{
            int a=100;
            public static void main(String args[]){
                            System.out.println(a);
           }
}

//오류나는이유는..순서상
// 1. java A 실행시 A.class를 현재폴더에서 찾는다.
// 2. 클래스A를 메모리에 로딩시킨다.(클래스A에 static이 선언된 모든것을 메모리에 올린다.)
// 3. 클래스A에 있는 main메서드를 호출한다.
// 즉, 위예제는 메인메서드가 먼저 메모리에 올라가있어서 a를 찾을수 없다.
   (주소를만들어주거나 변수a앞에 static을 붙히면 해결가능) 
 
[ex]
class A{
 static int a=100;      // 클래스변수(모든객체가 공유하는 변수)
 int b=200;             // 객체변수
 A(){
       a++;
       b++;
 }
}

class B{
 public static void main(String args[]){
  A o1=new A();                  // => 생성자 부름 => a=101
  A o2=new A();                  // => 생성자 부름 => a=102
  A o3=new A();                  // => 생성자 부름 => a=103
  System.out.println(A.a+","+o1.b);      // static이 붙은것은 클래스명.클래스변수  로 부른다. 
                                         // (static이붙어있어서 o1.a 나 A.a나 똑같음)
  System.out.println(A.a+","+o2.b);      // o1.a o2.a o3.a 로 불러도 a는 클래스변수이므로
                                         // 객체변수와 달리 101이 아닌 103이 출력됨
  System.out.println(A.a+","+o3.b);      // 즉, 클래스변수는 모든객체가 공유하기때문에 객체가
                                         // 생성될때마다 그 값은 변함
 }
}
 //103 201
 //103 201
 //103 201
 

[ex] 아래는 알맞게 수정하시오 
class Child{
      int candyNum=10;
      String name;
      Child(String n){
            name=n;
      }

      void eatCandy(){
            candyNum--;
            System.out.println("남은사탕수:"+candyNum);
      }
}

class A{
 public static void main(String args[]){
       Child child1=new Child("철수");
       Child child2=new Child("순이");
       child1.eatCandy();
       child2.eatCandy();
 }
}

[an]

class Child{
      static int candyNum=10;                  //static이라서 클래스에속함을 의미 => 각 개체에서 공통으로 사용(공유)
      String name;
      Child(String n){                             
           name=n;                                  
      }
      void eatCandy(){
           candyNum--;
           System.out.println("남은사탕수:"+candyNum);
     }
}

class A{
 public static void main(String args[]){
       Child child1=new Child("철수");
       Child child2=new Child("순이");
       child1.eatCandy();
       child2.eatCandy();
 } 
}





# static이 메서드앞에 선언될 때 : 편하게 사용하자..
 (멤버변수앞에 선언되는 static : 객체간에 어떤 변수를 공유하고자할때)

[ex]
class A{
     static void m1(){          //static이 붙는것은 주소를 만들필요없이 클래스명으로 바로 부를수있다.
           System.out.println(1);
     }
     void m2(){
           System.out.println(2);
     }
}

class B{
 public static void main(String args[]){
       A.m1();            // static이 붙은 메서드이기때문에 다른클래스에서 주소만들어줄필요없이
                          // 클래스명.메서드명 으로 바로 부를수 있다.
       A o=new A();       // 만약같은클래스에서 static이 붙은 매서드를 부를때에는 클래스명 생략가능

                          //  ==> A.m1()  --> m1()
       o.m2();            // 물론 static이붙은 클래스변수도 같은클래스안이면 생략가능 A.a --> a
 }
}


[ex]
class A{
     int a=100;
     public static void main(String args[]){      // 에러이유는... 실행순서상 static과
                                                  // 주소를만들어주는것이 메모리에 먼저 올라가고
            System.out.println(a);    //컴파일에러  // 메인메서드를 실행하기 때문에
                                                  // int a=100;이라는걸 인식할수 없음 ??
 }
}                    
// 해결책은 변수a를 클래스변수로 만들어주거나 아니면 아래 예제와 같이
// 클래스A의주소를 만들어주어 메모리에 올리면됨


[ex]
class A{
      static int a=100;
      int b=200;
      static void m1(){
            System.out.println(a);
            A o=new A();
            System.out.println(o.b);
      }
      void m2(){
            System.out.println(a);
            System.out.println(b);
      }

      public static void main(String args[]){
            m1();
            A o=new A();
            o.m2();
      }
}

 
//간단히 
class A{
        static B o=new B();
}

class B{
         void m(int n){
                   System.out.println(n);
         }
}

class C{
         public static void main(String args[]){
                 // B a=A.o;
                 // a.m(100);
                 A.o.m(100);        //위 두줄을 간단히 한줄로 나타낼수있음
          }                         //즉 static이라서 클래스이름으로 바로땡겨올수있음
}

 


#static블럭
     클래스가 메모리에 로딩될때 자동으로 호출됨!
     생성자보다 먼저 실행됨!!! 우선순위가 더 높음!! 즉, 객체 생성보다 먼저 실행됨!!
[ex] 
class A{
     static{
          System.out.println(1);
     }
}

class B{
     static{
          System.out.println(2);
     }
     public static void main(String args[]){
          A o1=new A();     //클래스 A라는게 사용되기전에 클래스A 호출됨 (A사용안하면 호출안됨)
          A o2=new A();     //즉 A객체 생성안하면 호출안됨!!!
          A o3=new A();
     }
}
//객체3번생성해도 클래스는 한번밖에 로딩안됨! 따라서 2 1 이 출력
//2 1

[ex]
static int a=100;
static{
     int b=100;
     System.out.println(a); //100
}
이렇게한다해도 메모리에 b는 올라가있지만 다른곳에서 클래스 이름으로 b를 부르거나 어떻게 부를수없음
왜냐하면 지역변수이기때문!!
 
 
 
 
 
#  final
 의미 : 마지막
 위치 : 클래스앞(상속안됨), 메서드앞(오버라이딩금지), 변수앞(재할당금지지)(멤버,매개,지역변수모두..)
[ex]
final class A{

}

class B extends A{      // 컴파일에러. 상속안됨

}


[ex] 오버라이딩조건
 1. 메서드의 선언부는 같아야한다.
 2. private, final, static 선언되어 있다면 오버라이딩할 수 없다.
          (오버라이딩할때 메서드앞에 static붙이면 오류는안남??)
class A{
 final void m(){

 }
}
class B extends A{
       void m(){                   // 컴파일에러, 오버라이딩안됨
 }
}



[ex] 
class A{
 void m(final int a){
  a=100;                 // 컴파일에러(재할당안됨)
 }
}
class B{
 void test(){
  A o=new A();
  o.m(0);
 }
}


[ex]
class A{
 void m(){
  final int a=100;
  a=200;         // 컴파일에러(재할당안됨)
 }
}




멤버변수앞의 final
[ex]
class A{
      final int a;
      A(){
            a=100;   // 생성자에서 값할당은 허용한다.(멤버변수앞에 final이 붙었을경우만!!)...
                     // 같은클래스에서만가능하고 다른클래스에선안됨...밑예제...
      }
 void m(){
       a=200;        // 컴파일에러...같은클래스내의 생성자에서만 가능하지 메서드에서는 안됨
 }
}


[ex]
/*
package java.lang;
public class Math{
      public static final double PI=3.14xxxxxxx;
      // ststic이라서 다른클래스에서 그냥 접근은 가능하나 final이라서 변경은 불가능 
}
*/

class A{
 void m(){                            //생성자로 바꿔주어도 ( A(){} ) 다른클래스라서 안됨
                                      // 이런식으로 고유 값을 변경 불가능하게 함!
       int r=10;
       //Math.PI=3.15;  컴파일에러
       System.out.println(2*Math.PI*r);
 }
}


# abstract
 의미 : 추상적(미완성)
 위치 : 클래스앞(객체생성안됨), 메서드앞(메서드를 오버라이딩하게끔 강제하기 위해서...)
 
[ex]
abstract class A{
      int a=100;
}
class B{
      public static void main(String args[]){
            A o=new A();   // 컴파일에러.... abstract라서 클래스 A는 주소생성(객체생성) 안됨!!!
       System.out.println(o.a);
 }
}


[ex] 추상메서드는 메서드의 body를 선언할 수 없다.
     추상메서드를 가진 클래스는 자동으로 추상클래스라고 선언해야한다.
class A{                 // 추상메서드를 가지고있는 클래스는 추상클래스로 선언해야함
                         // (반대는상관없음..추상클래스안에 일반메서드 O)

 abstract void m(){      //오류  ... 추상메서드는 바디를 가질수없다.
 
 }
}

//아래와같이해줘야 오류안남

//     abstract class A{
//           abstract void m();
//     }




abstract class A{
        abstract void m();
        void m2(){

        }
}
class B extends A{
        void m(){         //자식클래스가 추상될필요가없고 단지 부모의추상메서드를 오버라이딩만하면됨
        }
}
//핵심은 상속인데 부모가 추상메서드를 가지면 부모클래스도 추상클래스가되어야하는데 상속에의해
// 자식도 부모의 추상메서드를 가지게됨
// 따라서 자식클래스도 자동으로 추상클래스가되어야함... 하지만 이런건 좋지않음 그래서 abstract의
// 원래 목적은 자식도 추상클래스가 되는것이 아니고 부모의 메서드와 클래스가 추상이면
// 자식은 단지 부모의 추상메서드를 오버라이딩만하면됨 (자식클래스는 abstract일필요가없음)
// 즉, 부모의 추상메서드를 강제적으로 자식에서 오버라이딩하게끔하는 역활 

 
[ex] 
abstract class Animal{            //추상메서드를가진클래스라서 자동으로 추상클래스라고해야함
      abstract void sound();      //자손에서 오버라이딩을꼭해야 에러안남...추상메서드는
                                  //바디를 가질수없음(어차피 오버라이딩해야하기때문?)
}

class Dog extends Animal{
 void sound(){
       System.out.println("멍멍");
 }
}

class Cat extends Animal{
 void sound(){
       System.out.println("야옹");
 }
}

class SoundTest{
 void test(Animal animal){      // Animal animal=new Animal();  
                                // ==>   Animal animal=new Dog();     animal은 다형적변수  
          animal.sound();       // 다형적 변수는 오버라이딩 된것을 호출함                                                                                                    
 }                              // 물론 (Animal animal) 대신 (Dog animal) 해도 오류는안남(Dog만불렀기때문에)
}                               // 하지만 메인메서드에서 Cat도 부른다면 (Dog cat) 이되기때문에 오류...
                                // 부모인 (Animal animal)
                                // 해줘야 Cat도 부를수있음 ...
class A{
 public static void main(String args[]){
  Dog dog=new Dog();

  SoundTest st=new SoundTest();
  st.test(dog);                         //dog=new Dog();
 }
}
 
 
                                      
# 형변환
1 수치형간의 형변환
2 참조형간의 형변환


# 자바의 자료형
1 기본형(논리형,문자형char,정수형byte short int long,실수형float double) 
2 참조형(클래스형,배열형,인터페이스형)

8bit = 1byte
# 수치형의 값의 범위
 byte 8칸 < char,short 16칸 < int  32칸< long 64칸 < float 32칸 < double 64칸

[ex] 컴파일에러가 발생하는 이유는?
class A{
 public static void main(String args[]){
      float f=3.5;
 }
}

 
[ex]  숫자D : double 상수값
        숫자F : float 상수값
        숫자L : long 상수값
        0x숫자  : 16진수
        0숫자  : 8진수
        0b숫자  : 2진수 (jdk7)
class A{
 public static void main(String args[]){

  int a=0x36;     //16진수
  System.out.println(a); // 54  10진수로 결과값출력
  int b=037;     // 8진수
  System.out.println(b); // 31
  int c=0b101;   // 2진수
  System.out.println(c); // 5
 }
}

[ex]
class A{
 public static void main(String args[]){
  int a=0x1011;
  System.out.println(a);
  int b=0xab;
  System.out.println(b);
 }
}


[ex]
class A{
 public static void main(String args[]){
  for(char a='A'; a<='Z'; a++){
   System.out.println(a);
  }
 }
}     // A~Z

[ex]
class A{
 public static void main(String args[]){
  byte a=10;
  byte b=3;
  System.out.println(a & b);  // 2
  System.out.println(a | b);  // 11
  System.out.println(a ^ b);  // 9     //다르면 1 같으면 0
 }
}

 
[ex]
class A{
 public static void main(String args[]){
  B o=null;
  System.out.println( 3>0 || o.a<0 );  true          // 처음꺼만 트루면 뒤에꺼확인할필요없이
                                                     // 트루....속도가빠름(뒤에꺼는사실 오류이지만
                                                      // 뒤에꺼는실행조차안했음)
  //System.out.println( 3>0 | o.a<0 );      실행하면NullPointerException이 발생한다.    
  // | 하나짜리는 둘다(양쪽다) 검사
 }
}
class B{
 int a=1;
}