>  기사  >  Java  >  JAVA에서는 null

JAVA에서는 null

高洛峰
高洛峰원래의
2016-11-23 10:10:011336검색

Java 프로그래머에게 null은 골치 아픈 문제입니다. NPE(Null Pointer Exceptions)로 인해 괴롭힘을 당하는 경우가 많습니다. Java의 발명가조차도 이것이 자신의 큰 실수라고 인정했습니다. Java가 null을 유지하는 이유는 무엇입니까? Null은 한동안 존재해 왔으며 Java 발명가들은 Null이 해결한 문제보다 더 많은 문제를 야기한다는 것을 알고 있었던 것 같습니다. 그러나 Null은 여전히 ​​Java에 존재합니다.

Java의 설계 원칙은 모든 것을 단순화하는 것이므로 포인터, 연산자 오버로딩 및 다중 상속 구현에 시간을 낭비하지 않지만 null은 정반대이기 때문에 점점 더 놀랐습니다. 글쎄요, 저는 이 질문에 대한 답을 잘 모르겠습니다. 제가 아는 것은 Java 개발자와 오픈 소스 커뮤니티가 null을 아무리 비판하더라도 우리는 null과 공존해야 한다는 것입니다. null의 존재를 후회하기보다는 null에 대해 더 잘 배우고 null이 올바르게 사용되는지 확인해야 합니다.

Java에서 null을 배워야 하는 이유는 무엇인가요? null에 주의를 기울이지 않으면 Java는 NullPointerException으로 인해 어려움을 겪게 되고 고통스러운 교훈을 얻게 되기 때문입니다. 에너지 넘치는 프로그래밍은 팀, 고객, 사용자가 더욱 높이 평가할 예술입니다. 내 경험에 따르면 널 포인터 예외가 발생하는 주된 이유 중 하나는 Java에서 널에 대한 지식이 부족하기 때문입니다. 많은 사람들이 이미 null에 대해 잘 알고 있지만, 그렇지 않은 사람들을 위해 null에 대한 오래되고 새로운 내용을 배울 수 있습니다. Java의 null에 대한 몇 가지 중요한 지식을 다시 배워 보겠습니다.

Java에서 Null이 무엇인가요?

말씀드린 것처럼 null은 Java에서 매우 중요한 개념입니다. null의 원래 의도는 누락된 사용자, 리소스 또는 기타 항목과 같은 누락된 항목을 나타내는 것입니다. 그러나 1년 후, 골치 아픈 널 포인터 예외로 인해 Java 프로그래머들은 많은 괴롭힘을 당하게 되었습니다. 이 자료에서는 Java의 null 키워드에 대한 기본 세부 사항을 배우고, null 검사를 최소화하는 몇 가지 기술과 불쾌한 null 포인터 예외를 방지하는 방법을 살펴보겠습니다.

1) 우선 null은 Java의 public, static, final과 같은 키워드입니다. 대소문자를 구분하며 null을 Null 또는 NULL로 쓸 수 없으며 컴파일러는 이를 인식하지 못하고 오류를 보고합니다.

Object obj = NULL; // Not Ok
Object obj1 = null  //Ok

다른 언어를 사용하는 프로그래머라면 이런 문제가 있을 수 있지만, 이제는 IDE를 사용하면서 이러한 문제가 사소한 문제가 되었습니다. 이제 코드를 입력하면 Eclipse 및 Netbeans와 같은 IDE가 이 오류를 수정할 수 있습니다. 그러나 메모장, Vim, Emacs와 같은 다른 도구를 사용하면 이 문제는 귀중한 시간을 낭비하게 됩니다.

2) 모든 기본 유형에 기본값이 있는 것처럼 int의 기본값은 0, boolean의 기본값은 false, 엄밀히 말하면 null은 모든 참조 유형의 기본값입니다. 모든 객체 유형의 기본값입니다. 기본값이 false인 부울 변수를 생성하는 것과 마찬가지로 Java의 모든 참조 변수는 기본값으로 null을 갖습니다. 이는 멤버 변수, 지역 변수, 인스턴스 변수, 정적 변수 등 모든 변수에 적용됩니다(그러나 초기화되지 않은 지역 변수를 사용하면 컴파일러에서 경고합니다). 이 사실을 증명하기 위해 다음 코드와 같이 변수를 생성한 다음 해당 값을 인쇄하여 이 참조 변수를 관찰할 수 있습니다.

private static Object myObj;
public static void main(String args[]){
    System.out.println("What is value of myObjc : " + myObj);
}

What is value of myObjc : null


이는 정적 개체와 비정적 개체 모두에 해당됩니다. 여기에서 볼 수 있듯이 myObj를 정적 참조로 정의하여 기본 메서드에서 직접 사용할 수 있도록 했습니다. 기본 메서드는 정적 메서드이므로 비정적 변수를 사용할 수 없습니다.

3) 몇 가지 오해를 명확히 하고 싶습니다. null은 객체도 아니고 유형도 아닙니다. 이는 단지 특별한 값일 뿐이며 모든 참조 유형에 할당할 수 있으며 null을 모든 유형으로 변환할 수도 있습니다. 다음 코드를 살펴보십시오.

String str = null; // null can be assigned to String
Integer itr = null; // you can assign null to Integer also
Double dbl = null;  // null can also be assigned to Double
 
String myStr = (String) null; // null can be type cast to String
Integer myItr = (Integer) null; // it can also be type casted to Integer
Double myDbl = (Double) null; // yes it's possible, no error


컴파일 및 런타임 중에 null이 모든 참조 유형으로 캐스팅되는 것을 볼 수 있습니다. 모두 가능합니다. 런타임 중에는 널 포인터 예외가 발생하지 않습니다.

4) 참조 변수에는 null을 할당할 수 있지만, int, double, float, boolean 등 기본형 변수에는 null을 할당할 수 없습니다. 그렇게 하면 컴파일러에서 다음과 같은 오류가 발생합니다.

int i = null; // type mismatch : cannot convert from null to int
short s = null; //  type mismatch : cannot convert from null to short
byte b = null: // type mismatch : cannot convert from null to byte
double d = null; //type mismatch : cannot convert from null to double
 
Integer itr = null; // this is ok
int j = itr; // this is also ok, but NullPointerException at runtime


보시다시피 null을 기본 유형은 컴파일 오류를 발생시킵니다. 그러나 래퍼 클래스 객체에 null을 할당한 다음 해당 기본 유형에 객체를 할당하면 컴파일러는 이를 보고하지 않지만 런타임 시 null 포인터 예외가 발생합니다. 이는 Java의 자동 언박싱으로 인해 발생하며 다음 글머리 기호에서 살펴보겠습니다.

5) null 값을 포함하는 모든 래퍼 클래스는 Java가 기본 데이터 유형을 unboxing하고 생성할 때 null 포인터 예외를 발생시킵니다. 일부 프로그래머는 오토박싱이 null을 해당 기본 유형의 기본값(예: int의 경우 0, 부울 유형의 경우 false)으로 변환한다고 생각하는 실수를 범하지만, 아래와 같이 이는 올바르지 않습니다.

Integer iAmNull = null;
int i = iAmNull; // Remember - No Compilation Error


그러나 위의 코드 조각을 실행하면 콘솔에서 메인 스레드가 널 포인터 예외를 발생시키는 것을 볼 수 있습니다. HashMap 및 Integer 키 값을 사용할 때 이러한 오류가 많이 발생합니다. 다음 코드를 실행하면 오류가 나타납니다.

import java.util.HashMap;
import java.util.Map;
 
/**
 * An example of Autoboxing and NullPointerExcpetion
 *
 * @author WINDOWS 8
 */
public class Test {
    public static void main(String args[]) throws InterruptedException {
      Map numberAndCount = new HashMap<>();
      int[] numbers = {3, 5, 7,9, 11, 13, 17, 19, 2, 3, 5, 33, 12, 5};
 
      for(int i : numbers){
         int count = numberAndCount.get(i);
         numberAndCount.put(i, count++); // NullPointerException here
      }      
    }
}

   


输出:

Exception in thread "main" java.lang.NullPointerException
 at Test.main(Test.java:25)

   


这段代码看起来非常简单并且没有错误。你所做的一切是找到一个数字在数组中出现了多少次,这是Java数组中典型的寻找重复的技术。开发者首先得到以前的数值,然后再加一,最后把值放回Map里。程序员可能会以为,调用put方法时,自动装箱会自己处理好将int装箱成Interger,但是他忘记了当一个数字没有计数值的时候,HashMap的get()方法将会返回null,而不是0,因为Integer的默认值是null而不是0。当把null值传递给一个int型变量的时候自动装箱将会返回空指针异常。设想一下,如果这段代码在一个if嵌套里,没有在QA环境下运行,但是你一旦放在生产环境里,BOOM:-)

6)如果使用了带有null值的引用类型变量,instanceof操作将会返回false:

Integer iAmNull = null;
if(iAmNull instanceof Integer){
   System.out.println("iAmNull is instance of Integer");                            
 
}else{
   System.out.println("iAmNull is NOT an instance of Integer");
}

   


输出:

i
   
AmNull is NOT an instance of Integer

   


这是instanceof操作一个很重要的特性,使得对类型强制转换检查很有用

7)你可能知道不能调用非静态方法来使用一个值为null的引用类型变量。它将会抛出空指针异常,但是你可能不知道,你可以使用静态方法来使用一个值为null的引用类型变量。因为静态方法使用静态绑定,不会抛出空指针异常。下面是一个例子:

public class Testing {            
   public static void main(String args[]){
      Testing myObject = null;
      myObject.iAmStaticMethod();
      myObject.iAmNonStaticMethod();                            
   }
 
   private static void iAmStaticMethod(){
        System.out.println("I am static method, can be called by null reference");
   }
 
   private void iAmNonStaticMethod(){
       System.out.println("I am NON static method, don&#39;t date to call me by null");
   }

   


输出:

I am static method, can be called by null reference
Exception in thread "main" java.lang.NullPointerException
               at Testing.main(Testing.java:11)

   


8)你可以将null传递给方法使用,这时方法可以接收任何引用类型,例如public void print(Object obj)可以这样调用print(null)。从编译角度来看这是可以的,但结果完全取决于方法。Null安全的方法,如在这个例子中的print方法,不会抛出空指针异常,只是优雅的退出。如果业务逻辑允许的话,推荐使用null安全的方法。

9)你可以使用==或者!=操作来比较null值,但是不能使用其他算法或者逻辑操作,例如小于或者大于。跟SQL不一样,在Java中null==null将返回true,如下所示:

public class Test {
 
    public static void main(String args[]) throws InterruptedException {
 
       String abc = null;
       String cde = null;
 
       if(abc == cde){
           System.out.println("null == null is true in Java");
       }
 
       if(null != null){
           System.out.println("null != null is false in Java");
       }
 
       // classical null check
       if(abc == null){
           // do something
       }
 
       // not ok, compile time error
       if(abc > null){
 
       }
    }
}

   


输出:

null == null is true in Java

   


这是关于Java中null的全部。通过Java编程的一些经验和使用简单的技巧来避免空指针异常,你可以使你的代码变得null安全。因为null经常作为空或者未初始化的值,它是困惑的源头。对于方法而言,记录下null作为参数时方法有什么样的行为也是非常重要的。总而言之,记住,null是任何一个引用类型变量的默认值,在java中你不能使用null引用来调用任何的instance方法或者instance变量。


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.