C++ 프로그래머로서 우리는 이미 객체 지향 프로그래밍의 기본 개념을 마스터했으며 의심할 여지 없이 Java의 구문은 매우 친숙합니다. 실제로 Java는 원래 C++에서 파생되었습니다.
그러나 C++와 Java에는 여전히 몇 가지 중요한 차이점이 있습니다. 이러한 차이는 기술의 큰 발전을 의미한다고만 말하면 충분합니다. 이러한 차이점을 이해하면 Java가 왜 훌륭한 프로그래밍 언어인지 이해하게 됩니다. 이 부록에서는 Java와 C++를 구별하는 몇 가지 중요한 특성을 안내합니다.
(1). 가장 큰 장애물은 속도입니다. 해석된 Java는 C 실행 속도보다 약 20배 느립니다. Java 언어가 컴파일되는 것을 막을 수 있는 것은 아무것도 없습니다. 이 글을 쓰는 시점에서 작업 속도를 크게 높일 수 있는 일부 실시간에 가까운 컴파일러가 등장했습니다. 물론 더 대중적인 플랫폼을 위한 순수한 네이티브 컴파일러가 있을 것이라고 생각할 이유는 충분하지만, 그러한 컴파일러가 없으면 속도 제약으로 인해 Java가 해결할 수 없는 몇 가지 문제가 있을 것입니다.
(2) C++와 마찬가지로 Java도 두 가지 유형의 주석을 제공합니다.
(3) 모든 것은 클래스에 배치되어야 합니다. 전역 기능이나 전역 데이터가 없습니다. 전역 함수와 동등한 함수를 얻으려면 클래스에 정적 메서드와 정적 데이터를 배치하는 것이 좋습니다. 구조체, 열거형, 공용체 같은 것이 없고 단지 "클래스"만 있다는 점에 주목하세요!
(4) 모든 메소드는 클래스 본문에 정의됩니다. 그래서 C++ 관점에서 보면 모든 함수가 내장되어 있는 것처럼 보이지만 그렇지 않습니다. 내장 문제는 나중에 논의하겠습니다.
(5) Java에서는 클래스 정의가 C++와 거의 동일한 형태를 취합니다. 그러나 닫는 세미콜론은 없습니다. class foo 형식의 클래스 선언은 없고 클래스 정의만 있습니다.
class aType() void aMethod() {/* 方法主体*/} }
(6) Java에는 범위 연산자 "::"가 없습니다. Java는 모든 것에 점 표기법을 사용하지만 클래스의 요소만 정의할 수 있으므로 점 표기법에 대해 생각할 필요가 없습니다. 이러한 메서드 정의도 클래스 내부에 있어야 하므로 범위의 범위를 지정할 필요가 없습니다. 우리가 발견한 한 가지 차이점은 ClassName.methodName()을 사용하여 정적 메서드를 호출한다는 것입니다. 또한 패키지(package)의 이름은 마침표로 설정되며, import 키워드를 이용하여 C++의 "#include"의 일부 기능을 구현할 수 있다. 예를 들어 다음 문은 다음과 같습니다.
Import java.awt.*;
(#include는 import에 직접 매핑되지 않지만 사용하면 비슷한 느낌이 듭니다.)
( 7) C++와 유사하게 Java에는 보다 효율적인 액세스를 달성하기 위해 일련의 "기본 유형"이 포함되어 있습니다. Java에서 이러한 유형에는 boolean, char, byte, short, int, long, float 및 double이 포함됩니다. 모든 주요 유형의 크기는 고유하고 시스템에 독립적입니다(포팅 문제를 설명하기 위해). 이는 기계에 따라 확실히 성능에 어느 정도 영향을 미칠 것입니다. Java에서는 유형 검사 및 요구 사항이 더욱 엄격해졌습니다. 예:
조건식은 부울 유형만 사용할 수 있으며 정수는 사용할 수 없습니다.
X+Y와 같은 표현식의 결과를 사용해야 합니다. "부작용"을 달성하기 위해 "X+Y"만 사용할 수는 없습니다.
(8) char(문자) 유형은 국제적으로 통용되는 16비트 유니코드 문자 집합을 사용하므로 대부분의 국가의 문자를 자동으로 표현할 수 있습니다.
(9) 정적 참조 문자열은 자동으로 String 객체로 변환됩니다. C 및 C++와 달리 사용 가능한 독립적인 정적 문자 배열 문자열이 없습니다.
(10) Java는 "논리적" 오른쪽 시프트 연산자와 유사한 기능을 갖고 끝에 0 값을 삽입할 수 있는 세 개의 오른쪽 시프트 연산자 ">>>"를 추가합니다. ">>"는 이동하는 동안 부호 비트를 삽입합니다(예: "산술" 이동).
(11) 표면적으로 유사하기는 하지만 Java 배열은 C++에 비해 상당히 다른 구조를 사용하고 고유한 동작을 가지고 있습니다. 배열의 크기를 알려주는 읽기 전용 길이 멤버가 있습니다. 배열 경계를 초과하면 런타임 검사에서 자동으로 예외가 발생합니다. 모든 배열은 메모리 "힙"에 생성되며 한 배열을 다른 배열에 할당할 수 있습니다(단순히 배열 핸들을 복사함). 배열 식별자는 첫 번째 수준 개체이며 해당 메서드는 일반적으로 다른 모든 개체에서 사용할 수 있습니다.
(12) 기본 유형에 속하지 않는 모든 개체는 새 명령을 통해서만 생성할 수 있습니다. C++와 달리 Java에는 "스택에" 기본 유형이 아닌 객체를 생성하는 해당 명령이 없습니다. 모든 주요 유형은 새 명령을 사용하지 않고 스택에서만 생성할 수 있습니다. 모든 주요 클래스에는 자체 "래퍼" 클래스가 있으므로 new를 통해 동등한 메모리 "힙" 기반 객체를 생성할 수 있습니다(주 유형 배열은 예외입니다. C++ 할당과 같은 컬렉션을 통해 초기화하거나 new를 사용할 수 있습니다).
(13) Java에서는 미리 선언할 필요가 없습니다. 클래스나 메소드를 정의하기 전에 사용하려면 직접 사용하십시오. 컴파일러는 적절한 정의가 사용되도록 보장합니다. 따라서 C++와 달리 초기 참조와 관련된 문제가 발생하지 않습니다.
(14) Java에는 전처리기가 없습니다. 다른 라이브러리의 클래스를 사용하려면 import 명령을 사용하고 라이브러리 이름을 지정하면 됩니다. 전처리기와 유사한 매크로는 없습니다.
(15) Java는 네임스페이스 대신 패키지를 사용합니다. 모든 것이 클래스에 배치되고 클래스 이름에 대한 네임스페이스 분해와 같은 작업을 수행하는 "캡슐화"라는 메커니즘 덕분에 이름 지정 문제는 더 이상 문제가 되지 않습니다. 또한 패키지는 단일 라이브러리 이름으로 라이브러리 구성 요소를 수집합니다. 단순히 패키지를 "가져오기"만 하면 컴파일러가 나머지 작업을 수행합니다.
(16) 클래스 멤버로 정의된 객체 핸들은 자동으로 null로 초기화됩니다. 기본 클래스 데이터 멤버의 초기화는 Java에서 안정적으로 보장됩니다. 명시적으로 초기화되지 않은 경우 기본값(0 또는 이에 상응하는 값)을 얻습니다. 클래스 내에서 또는 빌더에서 정의하여 명시적으로 초기화(명시적 초기화)할 수 있습니다. 사용된 구문은 C++ 구문보다 이해하기 쉽고 정적 멤버와 비정적 멤버 모두에 대해 고정되어 있습니다. C++와 달리 정적 멤버의 저장 방식을 외부에서 정의할 필요가 없습니다.
(17) Java에는 C나 C++ 같은 포인터가 없습니다. new를 사용하여 객체를 생성하면 참조를 얻게 됩니다(이 책에서는 이를 항상 "핸들"이라고 부릅니다). 예를 들면 다음과 같습니다.
String s = new String("howdy");
그러나 C++ 참조는 생성될 때 초기화되어야 하며 다른 위치로 재정의될 수 없습니다. 그러나 Java 참조가 반드시 생성된 위치로 제한되는 것은 아닙니다. 상황에 따라 임의로 정의할 수 있으므로 포인터가 필요하지 않습니다. C 및 C++에서 포인터를 많이 사용하는 또 다른 이유는 모든 메모리 위치를 가리킬 수 있기 때문입니다(이로 인해 메모리 위치가 안전하지 않게 되고, 이것이 바로 Java가 이 지원을 제공하지 않는 이유입니다). 포인터는 종종 기본 변수 배열에서 이동하는 효율적인 수단으로 간주됩니다. Java를 사용하면 보다 안전한 형태로 동일한 목표를 달성할 수 있습니다. 포인터 문제에 대한 궁극적인 해결책은 "내재적 방법"입니다(부록 A에서 설명). 메서드에 포인터를 전달하는 것은 일반적으로 전역 함수가 없고 클래스만 있기 때문에 큰 문제를 일으키지 않습니다. 그리고 객체에 대한 참조를 전달할 수 있습니다. Java 언어는 처음에 "포인터를 전혀 사용하지 않습니다!"라고 주장했지만 많은 프로그래머가 묻기 시작하면서 포인터 없이 어떻게 작동할 수 있습니까? 그래서 나중에 "제한된 포인터를 사용하라"고 명시되었습니다. 그것이 '사실'인지 아닌지를 스스로 판단할 수 있는 지표다. 그러나 어쨌든 "산술"이라는 포인터는 없습니다.
(18) Java는 C++와 유사한 "생성자"를 제공합니다. 직접 정의하지 않으면 기본 빌더가 제공됩니다. 그리고 기본이 아닌 빌더가 정의되면 기본 빌더가 자동으로 정의되지 않습니다. 이는 C++과 동일합니다. 모든 인수가 참조로 전달되므로 복사 빌더가 없다는 점에 유의하세요.
(19) Java에는 "소멸자"가 없습니다. 변수에는 "범위" 문제가 없습니다. 개체의 "수명"은 가비지 수집기가 아니라 개체의 수명에 따라 결정됩니다. C++ "소멸자"와 다소 유사한 모든 클래스의 멤버인 finalize() 메서드가 있습니다. 그러나 finalize()는 가비지 수집기에 의해 호출되며 "리소스"(예: 열린 파일, 소켓, 포트, URL 등)를 해제하는 역할만 담당합니다. 특정 위치에서 작업을 수행하려면 특수 메서드를 생성하고 이를 호출해야 합니다. finalize()에 의존할 수는 없습니다. 반면에 C++의 모든 개체는 삭제되지만(또는 "해야") Java의 모든 개체가 "쓰레기"로 수집되는 것은 아닙니다. Java는 소멸자 개념을 지원하지 않으므로 필요한 경우 정리 방법을 생성할 때 주의가 필요합니다. 또한 기본 클래스와 클래스 내의 멤버 개체에 대해 모든 정리 메서드를 명시적으로 호출해야 합니다.
(20) Java에는 C++ 함수 오버로딩과 거의 동일하게 작동하는 메소드 "오버로딩" 메커니즘이 있습니다.
(21) Java는 기본 인수를 지원하지 않습니다.
(22) Java에는 goto가 없습니다. 채택한 무조건 점프 메커니즘은 현재 다중 중첩 루프에서 점프하는 데 사용되는 "break label" 또는 "continuestandard"입니다.
(23) Java는 단일 루트 계층 구조를 채택하므로 모든 객체는 루트 클래스 Object에서 균일하게 상속됩니다. C++에서는 어디에서나 새로운 상속 트리를 시작할 수 있으므로 많은 수의 트리가 포함된 "포리스트"를 보게 되는 경우가 많습니다. Java에서는 어쨌든 계층 구조가 하나만 있습니다. 이것이 표면적으로는 한계처럼 보일 수도 있지만, 모든 객체에는 적어도 하나의 Object 인터페이스가 있어야 한다는 것을 알고 있기 때문에 더 강력한 기능을 얻을 수 있는 경우가 많습니다. C++는 현재 단일 루트 구조를 적용하지 않는 유일한 OO 언어인 것 같습니다.
(24) Java에는 템플릿이나 다른 형태의 매개변수화된 유형이 없습니다. 이는 객체 참조를 수용하는 데 사용되는 Vector(벡터), Stack(스택) 및 Hashtable(해시 테이블)과 같은 일련의 컬렉션을 제공합니다. 이러한 컬렉션을 사용하면 다양한 요구 사항을 충족할 수 있습니다. 그러나 이러한 컬렉션은 C++ "표준 템플릿 라이브러리"(STL)처럼 빠르게 호출되도록 설계되지 않았습니다. Java 1.2의 새로운 컬렉션은 더욱 완벽해 보이지만 여전히 실제 템플릿을 효율적으로 사용하지 못합니다.
(25) "가비지 수집"은 Java에서 메모리 누수가 발생할 가능성이 훨씬 적지만 완전히 불가능하지는 않음을 의미합니다(저장 공간 할당을 위한 고유 메서드를 호출하면 가비지 수집기가 추적하고 모니터링할 수 없음). 그것). 그러나 메모리 누수 및 리소스 누수는 finalize()를 잘못 작성하거나 할당된 블록 끝에서 리소스를 해제함으로써 발생하는 경우가 많습니다(이 시점에서는 "소멸자"가 특히 편리합니다). 가비지 컬렉터는 C++를 기반으로 한 큰 발전으로 많은 프로그래밍 문제를 눈에 보이지 않게 해줍니다. 그러나 가비지 수집기가 처리할 수 없는 몇 가지 문제에는 적합하지 않습니다. 그러나 가비지 수집기의 수많은 장점으로 인해 이러한 단점은 사소해 보입니다.
(26) Java에는 멀티스레딩 지원 기능이 내장되어 있습니다. 특수 Thread 클래스를 사용하면 상속을 통해 새 스레드를 생성할 수 있습니다(run() 메서드는 폐기됨). 동기화된 키워드가 메소드의 유형 한정자로 사용되면 객체 수준에서 상호 배제가 발생합니다. 언제든지 하나의 스레드만 개체의 동기화 메서드를 사용할 수 있습니다. 반면에 동기화된 메서드가 시작된 후에는 먼저 개체를 "잠그어" 다른 동기화된 메서드가 해당 개체를 사용하지 못하도록 합니다. 이 메서드를 종료한 후에만 개체가 "잠금 해제"됩니다. 우리는 여전히 자체 "모니터" 클래스를 생성하여 스레드 간에 더 복잡한 동기화 메커니즘을 구현해야 할 책임이 있습니다. 재귀적인 동기화 방법은 잘 작동합니다. 스레드의 우선순위가 동일한 경우 시간 "슬라이싱"이 보장될 수 없습니다.
(27) C++처럼 선언 코드 블록을 제어하는 대신 액세스 한정자(공개, 비공개 및 보호)를 각 클래스 멤버의 정의에 넣습니다. "명시적"(모호하지 않은) 한정자를 지정하지 않으면 "친숙한" 한정자가 기본값으로 사용됩니다. 이는 동일한 패키지의 다른 요소도 이에 액세스할 수 있지만(C++에서 "친구"가 되는 것과 동일) 패키지 외부의 어떤 요소에서도 액세스할 수 없음을 의미합니다. 클래스와 클래스 내의 모든 메서드에는 파일 외부에서 "표시"되는지 여부를 결정하는 액세스 한정자가 있습니다. private 키워드는 일반적으로 Java에서는 거의 사용되지 않습니다. 왜냐하면 "친숙한" 액세스는 일반적으로 동일한 패키지에 있는 다른 클래스의 액세스를 제외하는 것보다 더 유용하기 때문입니다. 하지만 멀티스레드 환경에서는 프라이빗을 적절하게 사용하는 것이 매우 중요합니다. Java의 protected 키워드는 "상속자와 패키지의 다른 요소가 액세스할 수 있다"는 의미입니다. Java에는 C++의 protected 키워드와 동등한 것이 없습니다. 이는 "상속자만 액세스할 수 있습니다"를 의미합니다(이전에는 "private protected"를 이 목적으로 사용할 수 있었지만 이 키워드 조합은 취소되었습니다).
(28) 중첩 클래스. C++에서 중첩 클래스는 이름을 숨기고 코드 구성을 용이하게 하는 데 도움이 됩니다(그러나 C++의 "네임스페이스"로 인해 이름 숨김이 중복되었습니다). Java의 "캡슐화" 또는 "패키징" 개념은 C++의 네임스페이스와 동일하므로 이는 더 이상 문제가 되지 않습니다. Java 1.1에서는 내부 클래스 객체를 생성할 때 필요한 외부 클래스에 대한 핸들을 비밀리에 유지 관리하는 "내부 클래스" 개념을 도입했습니다. 이는 내부 클래스 객체가 어떤 조건 없이 외부 클래스 객체의 멤버에 액세스할 수 있음을 의미합니다. 마치 해당 멤버가 내부 클래스 객체에 직접적으로 종속된 것처럼 말입니다. 이는 콜백 문제에 대한 더 나은 솔루션을 제공합니다. C++에서는 멤버에 대한 포인터를 사용하여 이 문제를 해결합니다.
(29) 앞서 소개한 내부 클래스의 존재로 인해 Java에는 멤버를 가리키는 포인터가 없습니다.
(30) Java에는 "인라인" 메소드가 없습니다. Java 컴파일러는 재량에 따라 메소드를 포함할 수 있지만 이에 대해 더 이상 제어할 수는 없습니다. Java에서는 메소드의 final 키워드를 사용하여 임베딩을 "제안"할 수 있습니다. 그러나 함수 포함은 C++ 컴파일러에 대한 제안일 뿐입니다.
(31) Java中的继承具有与C++相同的效果,但采用的语法不同。Java用extends关键字标志从一个基础类的继承,并用super关键字指出准备在基础类中调用的方法,它与我们当前所在的方法具有相同的名字(然而,Java中的super关键字只允许我们访问父类的方法——亦即分级结构的上一级)。通过在C++中设定基础类的作用域,我们可访问位于分级结构较深处的方法。亦可用super关键字调用基础类构建器。正如早先指出的那样,所有类最终都会从Object里自动继承。和C++不同,不存在明确的构建器初始化列表。但编译器会强迫我们在构建器主体的开头进行全部的基础类初始化,而且不允许我们在主体的后面部分进行这一工作。通过组合运用自动初始化以及来自未初始化对象句柄的异常,成员的初始化可得到有效的保证。
public class Foo extends Bar { public Foo(String msg) { super(msg); // Calls base constructor } public baz(int i) { // Override super.baz(i); // Calls base method } }
(32) Java中的继承不会改变基础类成员的保护级别。我们不能在Java中指定public,private或者protected继承,这一点与C++是相同的。此外,在衍生类中的优先方法不能减少对基础类方法的访问。例如,假设一个成员在基础类中属于public,而我们用另一个方法代替了它,那么用于替换的方法也必须属于public(编译器会自动检查)。
(33) Java提供了一个interface关键字,它的作用是创建抽象基础类的一个等价物。在其中填充抽象方法,且没有数据成员。这样一来,对于仅仅设计成一个接口的东西,以及对于用extends关键字在现有功能基础上的扩展,两者之间便产生了一个明显的差异。不值得用abstract关键字产生一种类似的效果,因为我们不能创建属于那个类的一个对象。一个abstract(抽象)类可包含抽象方法(尽管并不要求在它里面包含什么东西),但它也能包含用于具体实现的代码。因此,它被限制成一个单一的继承。通过与接口联合使用,这一方案避免了对类似于C++虚拟基础类那样的一些机制的需要。
为创建可进行“例示”(即创建一个实例)的一个interface(接口)的版本,需使用implements关键字。它的语法类似于继承的语法,如下所示:
public interface Face { public void smile(); } public class Baz extends Bar implements Face { public void smile( ) { System.out.println("a warm smile"); } }
(34) Java中没有virtual关键字,因为所有非static方法都肯定会用到动态绑定。在Java中,程序员不必自行决定是否使用
以上就是java到底和C++有啥区别?的内容,更多相关内容请关注PHP中文网(www.php.cn)!