Java - 정말 "순수하게 객체 지향"인가요? Java의 세계를 탐구하고 이를 증명해 보겠습니다.
Java를 배우기 몇 년 전, 저는 Java가 "객체 지향 프로그래밍 패러다임"을 따른다는 것을 책에서 배웠습니다. Java 세계에서는 모든 것이 객체입니다. 심지어 문자열도 객체입니다(C 언어에서는 문자열이 문자 배열입니다). 당시 저는 Java가 객체 지향 언어라고 생각했습니다.
그런데 나중에 인터넷에서 많은 개발자들이 "자바 세계의 모든 것이 객체가 아니기 때문에 자바는 실제로 순수한 객체 지향이 아니다"라고 말하는 것을 보았습니다. 많은 주장은 다음 두 가지로 요약될 수 있습니다.
모든 정적 콘텐츠(정적 키로 수정된 변수 및 메서드)는 어떤 개체에도 속하지 않으므로 이는 물건을 물건.
모든 기본 유형(char, boolean, byte, short, int, long, float, double)은 일반 객체(예: " 사용)와 같은 작업을 수행할 수 없기 때문에 객체가 아닙니다. " 개체의 속성과 메서드에 액세스합니다.)
당시 저는 제 개인적인 지식과 경험이 부족하여 위의 주장을 쉽게 믿었고, 'Java는 순수한 객체지향 프로그래밍 언어가 아니다'라는 생각도 하기 시작했습니다. "
나중에 JVM 학습 과정에서 새로운 사실을 발견했습니다.
JVM은 객체를 생성할 때 실제로 두 개의 객체를 생성합니다. 객체:
하나는 인스턴스 객체입니다.
다른 하나는 Class 객체입니다. Class 객체는 JVM에서 한 번만 로드됩니다. 클래스의 정적 메서드와 정적 속성도 함께 로드됩니다. JVM은 Class 객체를 사용하여 위 객체와 같은 특정 인스턴스 객체를 생성합니다.
예를 들어 다음 Java 문에서는 두 개의 객체가 생성됩니다.
Employee emp = new Employee();
하나는 인스턴스 객체 emp이고, 다른 하나는 Class 객체입니다. Employee.class를 통해 참조할 수 있습니다. 이 클래스 개체에는 이 클래스에 의해 정의된 모든 정적 변수와 정적 메서드가 있습니다. 동시에 emp 개체를 통해 정적 콘텐츠에 액세스하면 해당 개체가 실제로 가리키는 개체를 찾을 수 있습니다. Employee.class입니다.
이것은 또한 또 다른 수수께끼를 드러냅니다. 왜 한 객체(emp 또는 emp2)에서 정적 콘텐츠가 변경되고 동시에 다른 객체에서도 변경되는 이유는 두 객체 모두 Employee.class의 동일한 객체 내에서 콘텐츠를 변경하기 때문입니다. .
이제 위에서 언급한 첫 번째 인수를 취소하겠습니다. 정적 콘텐츠가 실제로 개체에 속하는 것으로 확인되었기 때문입니다.
그러나 두 번째 주장도 확인하고 싶습니다. 앞서 언급했듯이 기본 유형은 Java의 객체가 아니며 객체와 유사한 작업을 수행할 수 없습니다. 이 문제를 해결하기 위해 Java는 각 기본 유형에 해당하는 래퍼 클래스를 공식적으로 출시했습니다(예: Integer는 int에 해당, Long은 long에 해당, Character는 char에 해당). 이제 객체 관련 작업을 수행하는 동안 래퍼 객체를 생성할 수 있습니다. 그리고 자동 언박싱 덕분에 해당 래퍼 클래스에 대한 참조에 기본 유형 값을 할당할 수 있습니다. 그러나 우리는 여전히 이러한 기본 유형에 대해 객체 작업을 수행할 수 없습니다. 해당 래퍼 클래스의 객체를 생성해야 합니다.
예:
Integer obj = new Integer(5); // here we can do i.toString(); int i = 5; // but we can't do i.toString() here
지금까지는 최종 사용자의 관점에서 “원래 카테고리는 객체가 아니다”라는 점을 확인할 수 있었습니다. (Java 개발자는 Java를 만드는 것이 아니라 사용하고 있기 때문에 Java의 최종 사용자입니다.)
JVM의 관점에서 보면 새로운 발견을 하게 됩니다.
사실 JVM의 관점에서는 모든 "원시형"을 객체로 취급합니다." 이를 증명하기 위해 한 가지 점은 Class 클래스의 소스 코드나 Javadoc의 Class 클래스 설명을 통해 찾을 수 있습니다
java.lang.Class 클래스의 소스 코드에 따르면 이 클래스의 주석은 다음과 같습니다. 🎜>
Java 공식 설명:Class 클래스의 인스턴스는 실행 중인 Java 애플리케이션의 클래스와 인터페이스를 나타냅니다. Enum은 일종의 클래스이고 Annotation은 일종의 인터페이스입니다. 배열은 동일한 요소 유형과 차원 수를 가진 모든 배열이 공유하는 클래스 객체로 반영되는 클래스에도 속합니다. 기본 Java 유형(boolean, byte, char, short, int, long, float 및 double) ), 키워드 void도 클래스 객체로 표현됩니다.참고 번역:
Class类的实例表示正在运行的Java应用程序的类和接口。像枚举是一种类和注解则是一种接口。每个数组也属于被反射作为由具有相同的元素类型和尺寸的数目的所有阵列共享一类对象的类。原始的Java类型(boolean, byte, char, short, int, long, float, and double)和关键字void也表示为Class对象。
同时也根据Javadoc中对Class.isPrimitive()方法的定义,来判断
Java官方描述:
public boolean isPrimitive()
Determines if the specified Class object represents a primitive type.
There are nine predefined Class objects to represent the eight primitive types and void. These are created by the Java Virtual Machine, and have the same names as t he primitive types that they represent, namely boolean,byte, char, short, int, long, float, and double.
These objects may only be accessed via the following public static final variables, and are the only Class objects for which this method returns true.
Returns:
true if and only if this class represents a primitive type
Since:
JDK1.1
参考翻译:
public boolean isPrimitive()
判断指定的Class对象是否代表一个基本类型。
一共有9种设定好的Class对象来表示对应的基本类型和void关键字。这些对象都是由JVM创建的。…
return当且仅当该类表示一个真正的基本类型
以上都说明,在JVM内部,其实原始类型就是对象。
当你打开 Javadoc 对 Class 类的定义中,通过 “CTRL+F ” 查找关键字 “primitive”, 将会发现证据在表面 “在JVM里,它把基本类型当作对象来处理的”。
我们可以再来看一个例子: Integer.TYPE,在这部分文档清晰记录着:
Java官方描述:
public static final Classc0f559cc8d56b43654fcbe4aa9df7b4a TYPE
The Class instance representing the primitive type int.
以上都说明,在JVM内部,其实原始类型就是对象。
那么,既然说 “JVM”会为所有的基本类型创建一个对象,那我们为什么还那么常用 “原始类型”, 而不是直接使用对应的包装类对象呢?
这是因为,为 “原始类型” 创建的对象,在JVM内部是很轻量级的,相对与我们直接创建的对应包装类对象做了许多优化; 也正因为轻量的缘故,这些原始类的功能就比较少(例如我们不能调用其内部的方法,因为他们内部已经优化成没有方法了)
使用实际的例子来说明,为什么我们更应该使用 “原始类型”:
“原始类型”有更快的速度(例如,下面的代码执行,在我们的机器上需要9秒,但当我把 Long 改成 long 之后,0秒内就完成了)
public static void main(String[] args) { long millis = System.currentTimeMillis(); Long sum = 0L; // uses Long, not long for (long i = 0; i <= Integer.MAX_VALUE; i++) { sum += i; } System.out.println(sum); System.out.println((System.currentTimeMillis() - millis) / 1000); }
“原始类型”允许我们直接使用 “==”来进行比较
new Integer(3) == new Integer(3); // false new Integer(100) == new Integer(100); // false Integer.valueOf(5) == Integer.valueOf(5); //true Integer.valueOf(200) == Integer.valueOf(200); //false
我们注意看第四句,输出结果确实为 “false” 。这个是因在 [-128; 127] 这个区间的265个整数会被 JVM 缓存存放, 所以在这个区间, JVM返回相同的对象;然而,超出这个区间, JVM就不再有缓存了,将会创建新的对象,所以结果是不等的。
所以总结一下是: 在JVM内部,原始类型就是被当作对象来处理的。但是我们开发者直接把 “原始类型” 当作对象使用,开发者应该使用对应的包装来。
위 내용은 자바가 순수 객체지향 언어인지 검증하기 위한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!