다음 내용은 원래 Java 인터뷰 질문 세트 이후에 제공된 책임있는 질문과 답변이며 답변이 완전히 수정되었습니다. 원래 질문에는 많은 중복 질문과 귀중한 질문이 있으며 많은 참조 답변도 잘못되었습니다. 수정 된 Java 인터뷰 질문 세트는 최신 버전의 JDK를 말하고 EJB 2.X와 같은 쓸모없는 컨텐츠를 제거하고 데이터 구조 및 알고리즘 관련 질문, 클래식 인터뷰 프로그래밍 질문, 대규모 웹 사이트 기술 아키텍처, 운영 체제, 데이터베이스, 디자인 패턴, UML 및 기타 컨텐츠를 보충합니다. 동시에, 해시 코드 방법의 설계, 쓰레기 수집의 힙 및 생성, Java, NIO.2 등의 새로운 동시 프로그래밍 등 많은 지식 포인트가 깊이 분석되었습니다. 저는 참여할 준비를하는 Java 프로그래머에게는 도움이 될 것입니다.
Java 프로그래머 인터뷰 질문 세트 (1-50)
1. Java 기본
1. 객체 지향적 특성의 측면은 무엇입니까?
답변 : 객체 지향 기능의 주요 측면은 다음과 같습니다.
1) 요약 : 추상화는 데이터 추상화 및 동작 추상화를 포함하여 객체 유형의 공통 특성을 객체 클래스로 요약하는 과정입니다. 추상화는 대상이 가지고있는 속성과 행동에만 초점을 맞추고, 이러한 행동의 세부 사항에주의를 기울이지 않습니다.
2) 상속 : 상속은 기존 클래스에서 상속 정보를 얻고 새로운 클래스를 만드는 과정입니다. 상속 정보를 제공하는 클래스를 부모 클래스 (Superclass, Base Class)라고합니다. 상속 정보를 얻는 클래스를 하위 클래스 (파생 클래스)라고합니다. 상속은 변화하는 소프트웨어 시스템에 어느 정도의 연속성을 제공하며, 상속은 또한 프로그램의 가변 요인을 캡슐화하는 중요한 수단입니다 (이해할 수없는 경우 Yan Hong 박사의 "Java 및 패턴"또는 "디자인 패턴 절제"에서 Bridge 모드에 대한 부분을 읽으십시오).
3) 캡슐화 : 일반적으로 캡슐화는 데이터를 작동하는 방법에 데이터를 바인딩하는 것이며, 정의 된 인터페이스를 통해서만 데이터에 대한 액세스를 달성 할 수 있습니다. 객체 지향의 본질은 현실 세계를 일련의 완전히 자율적이고 닫힌 객체로 묘사하는 것입니다. 우리가 수업에서 작성하는 방법은 구현 세부 사항을 캡슐화하는 것입니다. 우리는 클래스를 작성하는 것이 데이터 및 데이터 운영을 캡슐화하는 것입니다. 포장재는 숨겨 질 수있는 모든 것을 숨기고 외부 세계에 가장 간단한 프로그래밍 인터페이스 만 제공하는 것이라고 말할 수 있습니다 (일반 세탁기와 완전 자동 세탁기의 차이에 대해 생각할 수 있습니다. 완전 자동 세탁기가 더 잘 포장되어 있으므로 현재 사용하고있는 스마트 폰도 모든 것을 처리 할 수 있기 때문에 포장되어 있습니다).
4) 다형성 : 다형성은 다른 하위 유형의 물체가 동일한 메시지에 다르게 응답 할 수 있도록하는 것을 말합니다. 간단히 말해서, 동일한 객체 참조로 동일한 방법을 호출하지만 다른 일을하는 것입니다. 다형성은 컴파일 타임 다형성 및 런타임 다형성으로 나뉩니다. 객체의 방법이 외부 세계에 대한 대상이 제공하는 서비스로 간주되는 경우, 런타임 다형성은 다음과 같이 설명 할 수 있습니다. 시스템 A가 시스템 B가 제공하는 서비스에 액세스 할 때 시스템 B는 서비스를 제공하는 여러 가지 방법을 가지고 있지만 모든 것이 시스템 A에 투명합니다 (전기 면도기는 시스템 B와 마찬가지로 시스템 B가 전원 공급 장치 또는 AC에 의해 전원이 될 수 있습니다. 객체이지만 전원 공급 시스템의 기본 구현이 무엇인지, 전원을 얻는 방법). 메소드 과부하는 컴파일 타임 다형성 (사전 바인딩이라고도 함)을 구현하는 반면, 메소드는 런타임 다형성 (사후 바인딩이라고도 함)을 시행합니다. 런타임 다형성은 객체 지향에서 가장 중요한 것입니다. 다형성을 구현하려면 두 가지 일이 필요합니다. 1. 방법 다시 쓰기 (하위 클래스는 부모 클래스를 상속하고 부모 클래스에서 기존 또는 추상 방법을 다시 작성); 2. 객체 모델링 (동일한 참조가 동일한 방법으로 호출되도록 다른 서브 클래스 객체에 따라 다른 동작을 표시합니다).
2. 수정 자 공개, 개인, 보호 및 글쓰기가 아닌 (기본값) 액세스의 차이점은 무엇입니까?
답변 : 차이점은 다음과 같습니다.
범위는 BUN 서브 클래스와 동일합니다.
공개 √ √ √ √ √ √
보호 √ √ √ ×
기본값 √ √ × ×
개인 √ × × ×
클래스 멤버가 액세스 수정을 작성하지 않으면 기본값이 기본값입니다. 기본적으로 동일한 패키지의 다른 클래스의 경우 공개적이며 동일한 패키지에 있지 않은 다른 클래스의 경우 비공개입니다. 보호는 공개와 서브 클래스와 동일하며, 부모-자녀 관계가없는 동일한 패키지에없는 클래스에 비유됩니다.
3. 문자열이 가장 기본적인 데이터 유형입니까?
답변 : 아니요. Java에는 8 개의 기본 데이터 유형이 있습니다 : 바이트, 짧은, int, long, float, double, char 및 boolean; 기본 유형 (원시 유형) 및 열거 유형 (열거 유형)을 제외하고 나머지는 참조 유형 (참조 유형)입니다.
4. float f = 3.4; 맞습니까?
답 : 잘못. 3.4는 이중 정밀 번호입니다. 플로팅 포인트 유형 (플로트)에 이중으로 배정하면 정확도 손실 (다운 캐스팅, 좁은 것으로 알려진)이 발생하므로 Float F = (Float) 3.4를 캐스트해야합니다. 또는 플로트 f = 3.4f;.
5. 짧은 S1 = 1; S1 = S1 + 1; 잘못된 것이 있습니까? 짧은 S1 = 1; S1 += 1; 뭔가 잘못 되었나요?
답 : 짧은 S1 = 1; S1 = S1 + 1; 1은 int 유형이므로 S1+1 작동의 결과도 int 유형이며 값을 짧은 유형에 할당하려면 캐스트 유형이 필요합니다. 그리고 짧은 S1 = 1; S1 += 1; S1+= 1이므로 올바르게 컴파일 할 수 있습니다. s1 = (short) (s1 + 1)와 동일합니다. 암시 적 캐스트가 있습니다.
6. Java에 Goto가 있습니까?
답변 : GOTO는 Java로 예약 된 단어이며 현재 버전의 Java에는 사용되지 않습니다. (Java 키워드 목록은 Goto and Const를 포함하는 James Gosling (Java의 아버지)이 작성한 책 "The Java 프로그래밍 언어"책의 부록에 나와 있지만,이 두 가지는 현재 사용할 수없는 키워드이므로 일부 장소는 그것을 예약 한 단어라고 부릅니다. 실제로 예약 된 단어는 더 넓은 의미를 가지고 있어야합니다. 예약 된 단어)
7. Int와 Integer의 차이점은 무엇입니까?
답변 : Java는 거의 순수한 객체 지향 프로그래밍 언어이지만 프로그래밍의 편의를 위해 객체가 아닌 기본 데이터 유형이 여전히 소개됩니다. 그러나 이러한 기본 데이터 유형을 객체로 작동시키기 위해 Java는 각 기본 데이터 유형에 대한 해당 래퍼 클래스를 도입했습니다. INT의 포장 클래스는 정수입니다. JDK 1.5 이후, 자동 포장/미확가 부류 메커니즘이 도입되어 두 가지를 서로 변환 할 수 있습니다.
Java는 각 원시 유형에 대한 래퍼 유형을 제공합니다.
원시 유형 : 부울, 숯, 바이트, 짧은, int, int, float, double
포장 유형 : 부울, 캐릭터, 바이트, 짧은, 정수, 길고, 플로트, 더블
패키지 com.lovo; // 왜 hovertree.com에 대해 묻는 이유 {public static void main (String [] args) {Integer a = new Integer (3); 정수 b = 3; // 자동 상자 3로의 정수 유형 int c = 3; System.out.println (a == B); // False 두 참조는 동일한 객체 시스템을 참조하지 않습니다 .out.println (a == C); // true A a 자동 Unboxes int type으로 Unbox를 그런 다음 c}}와 비교합니다.추가 : 최근에 자동 포장 및 Unboxing과 관련된 인터뷰 질문이 발생했으며 코드는 다음과 같습니다.
public class test03 {public static void main (String [] args) {Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150; System.out.println (f1 == f2); System.out.println (f3 == f4); }} // hovertree.com이해하지 못하면 두 출력이 참이거나 거짓이라고 생각하기 쉽습니다. 우선, 4 가지 변수 F1, F2, F3 및 F4는 모두 정수 객체이므로 다음 == 작동은 값이 아니라 참조를 비교합니다. 포장의 본질은 무엇입니까? 정수 객체에 int 값을 할당하면 정수 클래스의 정적 메소드 값을 호출합니다. 소스 가치 코드를 보면 무슨 일이 일어나고 있는지 알게 될 것입니다.
공개 정적 정수 값 (int i) {if (i> = integercache.low && i <= integercache.high) return integercache.cache [i + (-integercache.low)]; 새로운 정수 (I)를 반환합니다. } // hovertree.comIntegerCache는 내부 클래스의 정수이며 코드는 다음과 같습니다.
/** * jls가 요구하는 * -128과 127 (포함) 사이의 값에 대한자가 옥스의 객체 아이덴티티 시맨틱을 지원하는 캐시. * * 캐시는 첫 번째 사용으로 초기화됩니다. 캐시 *의 크기는 {@code -xx : autoboxcachemax = <size>} 옵션에 의해 제어 될 수 있습니다. * VM 초기화 중에 java.lang.integer.integercache.high 속성 * * sun.misc.vm 클래스의 개인 시스템 속성에 설정되어 저장 될 수 있습니다. * hovertree.com */ private static class integercache {static final int low = -128; 정적 최종 INT High; 정적 최종 정수 캐시 []; static {// 높은 값은 int h = 127 특성으로 구성 될 수 있습니다. 문자열 integercachehighpropvalue = sun.misc.vm.getSavedProperty ( "java.lang.integer.integercache.high"); if (integercachehighpropvalue! = null) {try {int i = parseint (integercachehhighpropvalue); i = math.max (i, 127); // 최대 배열 크기는 정수입니다 .max_value h = math.min (i, integer.max_value- (-low) -1); } catch (numberformatexception nfe) {// 속성을 int로 구문 분석 할 수없는 경우 무시하십시오. }} High = H; 캐시 = 새 정수 [(High -Low) + 1]; int j = 낮음; for (int k = 0; k <cache.length; k ++) 캐시 [k] = 새 정수 (j ++); // 범위 [-128, 127]는 내재화되어야합니다 (JLS7 5.1.7) assert integercache.high> = 127; } private integercache () {}}간단히 말해서, 문자 값이 -128에서 127 사이 인 경우 새 정수 객체는 새롭지 않지만 상수 풀의 정수 객체는 직접 참조됩니다. 따라서 위의 인터뷰 질문에서 F1 == F2의 결과는 사실이며 F3 == F4의 결과는 False입니다. 인터뷰 질문이 더 단순할수록 더 많은 미스터리가 있으며 면접관은 상당한 기술이 필요합니다.
8. & & &의 차이점은 무엇입니까?
답변 : & 운영자의 두 가지 용도가 있습니다 : (1) 비트와 (2) 논리적. && 운영자는 단락 및 작동입니다. 논리와 단락의 차이는 매우 크지 만, 둘 다 연산자의 왼쪽 및 오른쪽 끝의 부울 값이 전체 표현식의 값에 충실해야합니다. &&는 왼쪽의 왼쪽 표현식 값이 false 인 경우 오른쪽의 표현식이 직접 단락되고 작업이 수행되지 않기 때문에 단락 작업이라고합니다. 여러 번 우리는 & 대신 &&를 사용해야 할 수도 있습니다. 예를 들어, 사용자 이름이 null이 아니고 빈 문자열이 아님을 확인할 때는 다음과 같이 작성해야합니다. username! = null &&! username.equals ( ""). 두 사람의 순서는 교환 할 수 없으며, & 연산자는 사용할 수 없습니다. 첫 번째 조건이 사실이 아닌 경우 문자열의 평등 비교를 전혀 수행 할 수 없기 때문에 NullPointerException이 생성됩니다. 참고 : 논리 또는 연산자 (|)와 단락 또는 연산자 (||)의 차이에 대해서도 마찬가지입니다.
추가 : JavaScript에 익숙하다면 단락 컴퓨팅의 힘을 더 많이 느낄 수 있습니다. JavaScript의 마스터가 되려면 단락 컴퓨팅을 연주하여 시작하십시오.
9. 메모리에서 스택, 힙 및 정적 저장 영역의 사용법을 설명하십시오.
답변 : 일반적으로 기본 데이터 유형의 변수, 객체 참조 및 기능 호출의 구내 저장은 모두 메모리의 스택 공간을 사용합니다. 그리고 새로운 키워드와 생성자를 통해 생성 된 객체는 힙 공간에 배치됩니다. 100, "Hello"및 직접 작성된 상수와 같은 프로그램의 리터럴은 정적 저장 영역에 배치됩니다. 스택 공간은 가장 빠르게 작동하지만 매우 작습니다. 일반적으로 많은 수의 객체가 힙 공간에 배치되며 하드 디스크의 가상 메모리를 포함한 전체 메모리를 힙 공간으로 사용할 수 있습니다.
문자열 str = 새 문자열 ( "hello");
위의 명령문에서 STR은 스택에 배치되며 새로 생성 된 문자열 객체는 힙에 배치되며 문자 그대로 "hello"는 정적 저장 영역에 배치됩니다.
보충 : 최신 버전의 Java는 "탈출 분석"이라는 기술을 사용하여 일부 로컬 객체를 스택에 배치하여 객체의 작동 성능을 향상시킬 수 있습니다.
10. 수학은 무엇입니까 (11.5)는 동일합니까? Math.round (-11.5)는 무엇입니까?
답변 : Math.Round (11.5)의 반환 값은 12이고 Math.Round (-11.5)의 반환 값은 -11입니다. 반올림의 원리는 매개 변수에 0.5를 추가 한 다음 반올림하는 것입니다.
11. Swtich가 바이트에서 행동 할 수 있고, 긴 행동을 할 수 있습니까?
답변 : 초기 JDK에서 Switch (Expr)에서 Expr은 바이트, 짧은, char 및 int 일 수 있습니다. 버전 1.5부터 Java는 열거 유형 (열거)을 소개했으며 Expr은 JDK의 버전 1.7에서 시작하여 String (String)에서도 열거 될 수 있습니다. 긴 유형은 허용되지 않습니다.
12. 가장 효율적인 방법을 사용하여 2 배 8을 계산 하시겠습니까?
답변 : 2 << 3 (왼쪽에서 3 비트를 움직이는 것은 2를 3의 전력으로 곱하는 것과 같습니다. 오른쪽에서 3 비트를 움직이는 것은 2로 3의 전력으로 나누는 것과 같습니다).
보충 : 우리가 쓴 클래스의 해시 코드 메소드를 다시 작성하면 아래에 표시된 코드가 표시 될 수 있습니다. 실제로, 우리는 왜 그러한 곱셈을 사용하여 해시 코드 (해시 코드)를 생성하는 이유를 이해하지 못하며이 숫자가 소수이며 왜 숫자 31이 일반적으로 선택됩니까? 처음 두 질문에 대한 답변에 대해 바이두를 할 수 있습니다. 곱셈 대신 시프트 및 뺄셈 작업을 사용할 수 있으므로 성능이 향상되므로 31을 선택하십시오. 이것에 대해 말하면, 당신은 다음과 같이 생각했을 것입니다 : 31 * num <==> (num << 5) - NUM, 왼쪽 5 비트를 5 번째 전력 (32)으로 곱하는 것과 동일하며 모든 VM은 31을 곱하는 것과 같습니다. 모든 VM은이 최적화를 자동으로 완료 할 수 있습니다.
패키지 com.loonstudio; 공개 클래스 PhoneNumber {Private Int AreaCode; 개인 문자열 접두사; 개인 문자열 라이너; @override public int hashcode () {Final int Prime = 31; int result = 1; 결과 = 프라임 * 결과 + 면적 코드; result = prime * result + ((linenumber == null)? 0 : linenumber.hashcode ()); result = prime * result + ((prefix == null)? 0 : prefix.hashcode ()); 반환 결과; } @override public boolean equals (Object obj) {if (this == obj) return true; if (obj == null) false를 반환합니다. if (getClass ()! = obj.getClass ()) false를 반환합니다. PhoneNumber Other = (PhoneNumber) obj; if (areaCode! = 기타. Areacode) false를 반환합니다. if (lineNumber == null) {if (Other.lineNumber! = null) false를 반환합니다. } else if (! lineNumber.equals (기타 .lineNumber)) false를 반환합니다. if (prefix == null) {if (기타 .prefix! = null) false를 반환합니다. } else if (! prefix.equals (기타 .prefix)) false를 반환합니다. 진실을 반환하십시오. }} // 왜 hovertree.com에 대해 묻습니다13. 배열에 대한 길이 () 메소드가 있습니까? 문자열의 길이 () 메소드가 있습니까?
답 : 배열에는 길이 () 메소드가 없지만 길이 속성이 있습니다. 문자열에는 길이 () 메소드가 있습니다. JavaScript에서, 문자열의 길이를 얻는 것은 길이 속성을 통해 얻어지며, 이는 Java와 쉽게 혼동됩니다.
14. Java에서는 현재 다중 중첩 루프에서 헤어지는 방법?
답 : 가장 바깥 쪽 루프 이전과 같은 마크를 추가 한 다음 Break a를 사용하십시오. 다중 루프가 파손될 수 있습니다. (Java는 Tagged Break 및 Contink 문을 지원하며 해당 기능은 C 및 C ++의 GOTO 문과 약간 유사하지만 GOTO를 피하는 것과 마찬가지로 프로그램이 더 우아하게 만들지 않기 때문에 태그가 지정된 브레이크를 피하고 종종 반대의 효과를 가져야 하므로이 구문이 실제로 더 좋습니다).
15. 생성자가 재정의 될 수 있습니까?
답변 : 생성자를 상속받을 수 없으므로 다시 작성할 수는 없지만 과부하 할 수 있습니다.
16. 두 객체의 값이 동일한 값 (x.equals (y) == true)를 가지지 만 해시 코드가 다를 수 있습니다. 이것이 맞습니까?
답변 : 아니요, 두 객체 x와 y가 x.equals (y) == true를 만족 시키면 해시 코드가 동일해야합니다. Java는 다음과 같이 Eqauls 방법과 해시 코드 방법을 규정합니다. (1) 두 객체가 동일하다면 (Equals 메소드가 true) 해시 코드 값이 동일해야합니다. (2) 두 객체의 해시 코드가 동일하다면 반드시 동일하지는 않습니다. 물론, 필요에 따라 할 필요는 없지만 위의 원리를 위반하면 컨테이너를 사용하면 세트 컬렉션에 동일한 객체가 나타날 수 있으며 새 요소를 추가하는 효율성이 크게 줄어든다는 것을 알 수 있습니다 (HASH 스토리지를 사용하는 시스템의 경우 해시 코드의 빈번한 충돌은 액세스 성능이 급격히 감소합니다).
보충 : 많은 Java 프로그램은 평등과 해시 코드 방법에 대해 알고 있지만 많은 사람들이 그것을 알고 있습니다. Joshua Bloch의 "효과적인 Java"(많은 소프트웨어 회사, "효과적인 Java", "Effection Java", "Java 프로그래밍 생각"및 "Refactoring : 기존 코드의 품질 향상"에서 Java 프로그래머가 꼭 읽지 않은 책입니다. Amazon에서 서둘러서 구매하는 방법은 다음과 같은 방법을 소개하는 방법입니다. 그리고 대칭 (x.equals (y)는 true, y.equals (x)도 true를 반환해야 함), 트랜 시력 (x.equals (y) 및 y.equals (z)도 true를 반환해야 함) 및 일관성 (x와 y가 언급 한 객체 정보가 수정되지 않은 경우 x.equals (y)에 대한 여러 호출 (x)에 대해 x, x. x. x. x. x. 고품질 평등 방법을 구현하는 요령에는 다음이 포함됩니다. 1. == 조작자를 사용하여 "매개 변수 가이 개체에 대한 참조인지 여부"를 확인합니다. 2. 연산자 인스턴스를 사용하여 "매개 변수가 올바른 유형인지 여부"를 확인하십시오. 3. 클래스의 주요 속성에 대해서는 객체에 전달 된 속성이 일치하는지 확인하십시오. 4. Equals 방법을 작성한 후에는 대칭, 전이성 및 일관성을 만족시키는 지 스스로에게 물어보십시오. 5. 다시 쓰기가 동일 할 때 항상 해시 코드를 다시 작성하십시오. 6. Equals 메소드 매개 변수의 객체 객체를 다른 유형으로 바꾸지 말고 다시 작성할 때 @override 주석을 잊지 마십시오.
17. 문자열 클래스를 상속받을 수 있습니까?
답 : 문자열 클래스는 최종 클래스이며 상속받을 수 없습니다.
보충 : 문자열 상속은 그 자체로 잘못된 동작입니다. 문자열 유형을 재사용하는 가장 좋은 방법은 상속 (IS-A)이 아닌 연관 (HAS-A)입니다.
18. 객체가 메소드에 매개 변수로 전달되면이 메소드는 객체의 속성을 변경하고 변경된 결과를 반환 할 수 있습니다. 그렇다면 여기에서 값 패스 또는 참조 패스입니까?
답 : 가치 전송입니다. Java 프로그래밍 언어는 값의 매개 변수 만 전달합니다. 객체 인스턴스가 매개 변수로 메소드로 전달되면 매개 변수의 값은 객체에 대한 참조입니다. 호출 프로세스 중에 객체의 속성을 변경할 수 있지만 객체에 대한 참조는 변경되지 않습니다. C ++ 및 C#에서, 참조를 전달하거나 매개 변수를 전송하여 전달 된 매개 변수의 값을 변경할 수 있습니다.
보충 : Java 8에서 개선되지 않은 Java에서 참조를 통과하지 못하는 것은 실제로 불편합니다. 정확히 이러한 방식으로 많은 수의 래퍼 클래스가 Java로 작성된 코드에 나타납니다 (메소드 호출을 통해 수정 해야하는 참조를 래퍼 클래스로 전달한 다음 래퍼 객체를 메소드로 전달합니다). 이 접근법은 특히 C 및 C ++에서 Java 프로그래머로 변환하는 개발자에게만 코드를 부풀게 만들 것입니다.
19. String과 StringBuilder와 StringBuffer의 차이점은 무엇입니까?
답변 : Java 플랫폼은 문자열과 Stringbuffer/StringBuilder의 두 가지 유형의 문자열을 제공하여 문자열을 저장하고 조작 할 수 있습니다. 여기서 문자열은 읽기 전용 문자열이므로 문자열로 참조 된 문자열의 내용을 변경할 수 없습니다. StringBuffer 및 StringBuilder 클래스로 표시되는 문자열 객체는 직접 수정할 수 있습니다. StringBuilder는 JDK 1.5에 도입되었습니다. 그것은 StringBuffer의 방법과 정확히 동일합니다. 차이는 단일 스레드 환경에서 사용된다는 것입니다. 모든 측면은 동기화로 수정되지 않기 때문에 StringBuffer보다 약간 더 효율적입니다.
보충 1 : 인터뷰 질문이 있습니다. +를 사용하기 위해 스트링 연결을 사용하는 것을 사용하는 상황이 있습니까? 연결 후 얻은 문자열이 정적 저장 영역에 이미 존재하는 경우 문자열 연결에 +를 사용하는 것이 StringBuffer/StringBuilder의 Append 메소드보다 낫습니다.
Supplement 2 : 다음은 인터뷰 질문으로, 프로그램의 출력에 정답을 줄 수 있는지 확인하십시오.
패키지 com.lovo; // hovertree.com에 대해 묻는 이유 public class Stringequaltest {public static void main (String [] args) {문자열 a = "프로그래밍"; 문자열 b = 새 문자열 ( "프로그래밍"); 문자열 c = "프로그램" + "Ming"; System.out.println (a == b); System.out.println (a == C); System.out.println (a.equals (b)); System.out.println (a.equals (c)); System.out.println (a.intern () == B.intern ()); }}20. 과부하와 재정의 차이. 오버로드 된 메소드를 반환 유형에 따라 구별 할 수 있습니까?
답 : 두 가지 방법 과부하 및 재 작성은 다형성을 구현하는 방법입니다. 차이점은 전자가 컴파일 타임 다형성을 구현하는 반면, 후자는 런타임 다형성을 구현한다는 것입니다. 과부하는 클래스에서 발생합니다. 이름이 동일한 메소드가 다른 매개 변수 목록 (다른 매개 변수 유형, 다른 매개 변수 또는 둘 다)을 갖는 경우 과부하로 간주됩니다. 하위 클래스와 상위 클래스 사이에 다시 쓰기가 발생합니다. 다시 쓰기는 서브 클래스의 재 작성 메소드와 상위 클래스가 상위 클래스의 다시 작성된 메소드와 동일한 리턴 유형을 가지며, 이는 상위 클래스의 재 작성 메소드보다 더 잘 액세스 할 수 있으며 상위 클래스의 재 작성 방법 (Rischer의 대체 원리)보다 더 많은 예외를 선언 할 수 없습니다. 과부하에는 반품 유형에 대한 특별한 요구 사항이 없습니다.
보충 : Huawei는 한 번 인터뷰 질문에서 질문을 한 번 질문했습니다. 반환 유형을 기반으로 과부하를 구별 할 수없는 이유는 무엇입니까?
21. JVM로드 클래스 파일의 원리와 메커니즘을 설명 하시겠습니까?
답변 : JVM의 클래스로드는 클래스 로더 (클래스 로더)와 하위 클래스에 의해 구현됩니다. Java의 클래스 로더는 중요한 Java 런타임 시스템 구성 요소로 런타임에 클래스 파일에서 클래스를 찾고로드하는 데 책임이 있습니다.
다시 채우다:
1. Java의 크로스 플랫폼 특성으로 인해 컴파일 된 Java 소스 프로그램은 실행 가능한 프로그램이 아니라 하나 이상의 클래스 파일입니다. Java 프로그램이 클래스를 사용해야하는 경우 JVM은 클래스가로드, 연결 (검증, 준비 및 구문 분석)을 제공하고 초기화되었는지 확인합니다. 클래스로드는 클래스 .class 파일에서 메모리로 데이터를 읽는 것을 말합니다. 일반적으로 바이트 배열을 작성하여 .class 파일로 읽은 다음로드 된 클래스에 해당하는 클래스 객체를 생성합니다. 로딩이 완료된 후에는 클래스 객체가 여전히 불완전하므로 현재 클래스를 사용할 수 없습니다. 클래스가로드되면 연결 단계로 들어갑니다. 이 단계에는 검증, 준비 (정적 변수에 대한 메모리 할당 및 기본 초기 값 설정) 및 구문 분석 (기호 참조를 직접 참조로 교체)의 세 단계가 포함됩니다. 마지막으로, JVM은 다음을 포함하여 클래스를 초기화합니다. 1. 클래스에 직접 상위 클래스가 있고 클래스가 초기화되지 않은 경우 부모 수업이 먼저 초기화됩니다. 2. 클래스에 초기화 명세서가있는 경우 이러한 초기화 문은 차례로 실행됩니다.
2. 클래스 로딩은 루트 로더 (부트 스트랩), 확장자 로더 (확장), 시스템 로더 (시스템) 및 사용자 정의 클래스 로더 (java.lang.classloader)를 포함하여 클래스 로더에 의해 수행됩니다. JDK 1.2부터 클래스 로딩 프로세스는 아버지 위임 메커니즘 (PDM)을 채택합니다. PDM은 Java 플랫폼의 보안을 더 잘 보장합니다. 이 메커니즘에서 JVM의 자체 부트 스트랩은 루트 로더이며 다른 로더에는 하나의 상위 클래스 로더가 있습니다. 클래스로드는 먼저 부모 클래스 로더에로드를 요청하고, 상위 클래스 로더는 무력한 경우 서브 클래스 로더에 의해서만로드됩니다. JVM은 부트 스트랩에 대한 Java 프로그램에 대한 참조를 제공하지 않습니다. 여러 클래스 로더에 대한 몇 가지 지침은 다음과 같습니다.
a) 부트 스트랩 : 일반적으로 로컬 코드를 사용하여 구현되며 JVM (Rt.jar)의 기본 핵심 클래스 라이브러리를로드 할 책임이 있습니다.
b) 확장 : java.ext.dirs 시스템 속성에 의해 지정된 디렉토리에서 클래스 라이브러리를로드하고, 상위 로더는 부트 스트랩입니다.
c) 시스템 : 응용 프로그램 클래스 로더라고도 알려진 부모 클래스는 확장입니다. 가장 널리 사용되는 클래스 로더입니다. 환경 변수 classpath 또는 시스템 속성 Java.class.path로 지정된 디렉토리에서 클래스를 기록하며 사용자 정의 로더의 기본 상위 로더입니다.
22. 중국어를 숯 유형 변수에 저장할 수 있습니까? 왜?
답변 : Char 유형은 Java에 사용 된 인코딩이 유니 코드이기 때문에 중국어를 저장할 수 있습니다 (특정 인코딩은 선택되지 않으며 문자는 문자 세트 번호에서 직접 사용됩니다. 이는 유일한 통합 방법입니다). 숯 유형은 2 바이트 (16 비트)를 차지하므로 중국어를 넣는 것은 문제가되지 않습니다.
보충 : 유니 코드를 사용한다는 것은 문자가 JVM 내부와 외부의 다른 징후를 가지고 있으며 JVM 내부의 유니 코드임을 의미합니다. 이 문자가 JVM에서 외부로 전송되면 (예 : 파일 시스템에 저장) 인코딩 변환이 필요합니다. 따라서 Java에는 바이트 스트림 및 문자 스트림뿐만 아니라 InputStreamReader 및 OutputStreamReader와 같은 문자 스트림과 바이트 스트림 사이를 변환하는 변환 스트림이 있습니다. 이 두 클래스는 바이트 스트림과 문자 스트림 사이의 어댑터 클래스이며 변환을 인코딩하는 작업을 수행합니다. C 프로그래머의 경우, 이러한 인코딩 변환을 완료하기 위해서는 아마도 Union (Union/Community) 공유 메모리의 특성에 의존 할 것입니다.
23. 추상 클래스와 인터페이스의 유사점과 차이점은 무엇입니까?
답 : 추상 클래스와 인터페이스를 모두 인스턴스화 할 수는 없지만 추상 클래스 및 인터페이스 유형에 대한 참조는 정의 될 수 있습니다. 클래스가 추상 클래스를 상속하거나 인터페이스를 구현하는 경우 모든 추상 방법을 구현해야합니다. 그렇지 않으면 클래스는 여전히 추상 클래스로 선언해야합니다. 생성자는 추상 클래스에서 정의 될 수 있고 추상적 인 방법과 구체적인 방법이있을 수 있기 때문에 인터페이스는 추상 클래스보다 더 추상적입니다. 그리고 생성자는 인터페이스에서 정의 할 수 없으며 그 중 모든 방법은 추상 방법입니다. 추상 클래스의 회원은 비공개, 기본, 보호 및 공개 일 수 있으며 인터페이스의 구성원은 모두 공개됩니다. 멤버 변수는 추상 클래스에서 정의 될 수 있으며 인터페이스에 정의 된 멤버 변수는 실제로 상수입니다. 추상적 인 방법을 가진 수업은 추상 클래스로 선언되어야하며, 추상 클래스에는 반드시 추상적 인 방법이있는 것은 아닙니다.
24. 정적 중첩 클래스와 내부 클래스 (내부 클래스)의 차이점은 무엇입니까?
답변 : 정적 중첩 클래스는 정적으로 선언 된 내부 클래스이며 외부 클래스 인스턴스에 의존하지 않고 인스턴스화 할 수 있습니다. 외부 클래스가 인스턴스화 된 후에는 일반적인 내부 클래스를 인스턴스화해야하며 구문은 아래와 같이 매우 이상하게 보입니다.
패키지 com.lovo; / ** * 포커 클래스 (포커 데크) hovertree.com에 대해 묻는 이유 * */ public class poker {private static string [] suites = { "스페이드", "로즈", "잔디 꽃", "큐브"}; 개인 정적 int [] faces = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; 개인 카드 [] 카드; / *** 생성자**/ public poker () {cards = 새 카드 [52]; for (int i = 0; i <suites.length; i ++) {for (int J = 0; }}} / ** * Shuffle (random of mister) * * / public void shuffle () {for (int i = 0, len = cards.length; i <len; i ++) {int index = (int) (math.random () * len); 카드 온도 = 카드 [색인]; 카드 [index] = 카드 [i]; 카드 [i] = 온도; }} / *** 카드 거래* @param index 거래의 위치** / public card deal (int index) {return card [index]; } / ** * 카드 클래스 (포커 조각) * [내부 클래스] * @author luo hao * / public class card {private String suite; // 개인 int 얼굴에 맞습니다. // PORCER PUBLIC CARD (String Suite, Int Face) {this.suite = Suite; this.face = 얼굴; } @override public String toString () {String facest = ""; 스위치 (FACE) {CASE 1 : FACESTR = "A"; 부서지다; 사례 11 : FaceStrest = "J"; 부서지다; 사례 12 : FaceStrest = "Q"; 부서지다; 사례 13 : FaceStrest = "k"; 부서지다; 기본값 : FaceStrem = String.Valueof (Face); } 반환 Suite + Facest; }}} 테스트 클래스 :
패키지 com.lovo; 클래스 PokerTest {public static void main (String [] args) {poker poker = new Poker (); poker.shuffle (); // 셔플 포커 .card c1 = poker.deal (0); // 비 정적 내부 클래스 카드의 첫 번째 카드를 제공합니다. // 카드 객체는 외부 클래스 포커 객체 poker.card c2 = poker.new card ( "Red Heart", 1)를 통해서만 생성 될 수 있습니다. // 카드를 직접 만들어 System.out.println (C1); // 첫 번째 system.out.println (C2); // 인쇄 : Red Heart a}} // 왜 hovertree.com에 대해 묻습니다.25. Java에 메모리 누출이 있습니까? 간단히 설명 해주세요.
답변 : 이론적으로 Java는 GC (Garbage Collection Mechanism)가 있기 때문에 메모리 누출이 없습니다 (이것은 Java가 서버 측 프로그래밍에 널리 사용되는 중요한 이유이기도합니다). 그러나 실제 발전에서는 쓸모 없지만 접근 가능한 객체가있을 수 있으며 이러한 객체는 GC로 재활용 할 수 없으며 메모리 누출이 발생합니다. 예를 들어 Hibernate 세션 (레벨 1 캐시)의 객체는 지속적이며 쓰레기 수집기는 이러한 물체를 재활용하지 않지만 이러한 물체에는 쓸모없는 쓰레기 물체가있을 수 있습니다. 다음 예제는 또한 Java의 메모리 누출을 보여줍니다.
패키지 com.lovo; // 왜 hovertree.com에 대해 묻는 이유 java.util.arrays; java.util.emptystackexception import; 공개 클래스 mystack <t> {private t [] 요소; 개인 int 크기 = 0; 개인 정적 최종 최종 int init_capacity = 16; public mystack () {elements = (t []) 새 개체 [init_capacity]; } public void push (t elem) {ensurecapacity (); 요소 [size ++] = elem; } public t pop () {if (size == 0) 새 nick emptystackexception (); 반환 요소 [-크기]; } private void ensureCapacity() { if(elements.length == size) { elements = Arrays.copyOf(elements, 2 * size + 1); }}}上面的代码实现了一个栈(先进后出(FILO))结构,乍看之下似乎没有什么明显的问题,它甚至可以通过你编写的各种单元测试。然而其中的pop方法却存在内存泄露的问题,当我们用pop方法弹出栈中的对象时,该对象不会被当作垃圾回收,即使使用栈的程序不再引用这些对象,因为栈内部维护着对这些对象的过期引用(obsolete reference)。在支持垃圾回收的语言中,内存泄露是很隐蔽的,这种内存泄露其实就是无意识的对象保持。如果一个对象引用被无意识的保留起来了,那么垃圾回收器不会处理这个对象,也不会处理该对象引用的其他对象,即使这样的对象只有少数几个,也可能会导致很多的对象被排除在垃圾回收之外,从而对性能造成重大影响,极端情况下会引发Disk Paging(物理内存与硬盘的虚拟内存交换数据),甚至造成OutOfMemoryError。
26、抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?
答:都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。
27、静态变量和实例变量的区别?
答:静态变量是被static修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;实例变量必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。在Java开发中,上下文类和工具类中通常会有大量的静态成员。
28、是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?
答:不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,因此在调用静态方法时可能对象并没有被初始化。
29、如何实现对象克隆?
答:有两种方式:
1.实现Cloneable接口并重写Object类中的clone()方法;
2. Implement the Serializable interface, and implement cloning through object serialization and deserialization, which can realize true deep cloning. 코드는 다음과 같습니다.
package com.lovo; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class MyUtil { private MyUtil() { throw new AssertionError(); } public static <T> T clone(T obj) throws Exception { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bout); oos.writeObject(obj); ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bin); return (T) ois.readObject(); // 说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义// 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源} } //何问起hovertree.com下面是测试代码:
package com.lovo; import java.io.Serializable; /** * 人类* @author 骆昊* */ class Person implements Serializable { private static final long serialVersionUID = -9102017020286042305L; private String name; // 姓名private int age; // 年龄private Car car; // 座驾public Person(String name, int age, Car car) { this.name = name; this.age = age; this.car = car; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", car=" + car + "]"; } } /** * 小汽车类* @author 骆昊* */ class Car implements Serializable { private static final long serialVersionUID = -5713945027627603702L; private String brand; // 品牌private int maxSpeed; // 最高时速public Car(String brand, int maxSpeed) { this.brand = brand; this.maxSpeed = maxSpeed; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public int getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; } @Override public String toString() { return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]"; } } //何问起hovertree.comclass CloneTest { public static void main(String[] args) { try { Person p1 = new Person("Hao LUO", 33, new Car("Benz", 300)); Person p2 = MyUtil.clone(p1); // 深度克隆p2.getCar().setBrand("BYD"); // 修改克隆的Person对象p2关联的汽车对象的品牌属性// 原来的Person对象p1关联的汽车不会受到任何影响// 因为在克隆Person对象时其关联的汽车对象也被克隆了System.out.println(p1); } catch (Exception e) { e.printStackTrace(); } } }注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。
30、GC 是什么?为什么要有GC?
答: GC是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。Java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() ,但JVM可以屏蔽掉显示的垃圾回收调用。
垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低优先级的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。在Java诞生初期,垃圾回收是Java最大的亮点之一,因为服务器端的编程需要有效的防止内存泄露问题,然而时过境迁,如今Java的垃圾回收机制已经成为被诟病的东西。移动智能终端用户通常觉得iOS的系统比Android系统有更好的用户体验,其中一个深层次的原因就在于Android系统中垃圾回收的不可预知性。
补充:垃圾回收机制有很多种,包括:分代复制垃圾回收、标记垃圾回收、增量垃圾回收等方式。标准的Java进程既有栈又有堆。栈保存了原始型局部变量,堆保存了要创建的对象。Java平台对堆内存回收和再利用的基本算法被称为标记和清除,但是Java对其进行了改进,采用“分代式垃圾收集”。这种方法会跟Java对象的生命周期将堆内存划分为不同的区域,在垃圾收集过程中,可能会将对象移动到不同区域:
伊甸园(Eden):这是对象最初诞生的区域,并且对大多数对象来说,这里是它们唯一存在过的区域。
幸存者乐园(Survivor):从伊甸园幸存下来的对象会被挪到这里。
终身颐养园(Tenured):这是足够老的幸存对象的归宿。年轻代收集(Minor-GC)过程是不会触及这个地方的。当年轻代收集不能把对象放进终身颐养园时,就会触发一次完全收集(Major-GC),这里可能还会牵扯到压缩,以便为大对象腾出足够的空间。
与垃圾回收相关的JVM参数:
-Xms / -Xmx --- 堆的初始大小/ 堆的最大大小
-Xmn --- 堆中年轻代的大小
-XX:-DisableExplicitGC --- 让System.gc()不产生任何作用
-XX:+PrintGCDetail --- 打印GC的细节
-XX:+PrintGCDateStamps --- 打印GC操作的时间戳
31、String s=new String(“xyz”);创建了几个字符串对象?
答:两个对象,一个是静态存储区的"xyz",一个是用new创建在堆上的对象。
32、接口是否可继承(extends)接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)?
答:接口可以继承接口。抽象类可以实现(implements)接口,抽象类可继承具体类,但前提是具体类必须有明确的构造函数。
33、一个“.java”源文件中是否可以包含多个类(不是内部类)?有什么限制?
答:可以,但一个源文件中最多只能有一个公开类(public class)而且文件名必须和公开类的类名完全保持一致。
34、Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口?
答:可以继承其他类或实现其他接口,在Swing编程中常用此方式来实现事件监听和回调。
35、内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制?
答:一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员。
36、Java 中的final关键字有哪些用法?
答: (1)修饰类:表示该类不能被继承;(2)修饰方法:表示方法不能被重写;(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。
37、指出下面程序的运行结果:
class A{ static{ System.out.print("1"); } public A(){ System.out.print("2"); } } class B extends A{ static{ System.out.print("a"); } public B(){ System.out.print("b"); } } //何问起hovertree.compublic class Hello{ public static void main(String[] args){ A ab = new B(); ab = new B(); } }答:执行结果:1a2b2b。创建对象时构造器的调用顺序是:先初始化静态成员,然后调用父类构造器,再初始化非静态成员,最后调用自身构造器。
38、数据类型之间的转换:
1)如何将字符串转换为基本数据类型?
2)如何将基本数据类型转换为字符串?
답변:
1)调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型;
2)一种方法是将基本数据类型与空字符串(””)连接(+)即可获得其所对应的字符串;另一种方法是调用String 类中的valueOf(…)方法返回相应字符串
39、如何实现字符串的反转及替换?
答:方法很多,可以自己写实现也可以使用String或StringBuffer / StringBuilder中的方法。有一道很常见的面试题是用递归实现字符串反转,代码如下所示:
public static String reverse(String originStr) { if(originStr == null || originStr.length() <= 1) return originStr; return reverse(originStr.substring(1)) + originStr.charAt(0); } //何问起hovertree.com40、怎样将GB2312编码的字符串转换为ISO-8859-1编码的字符串?
答:代码如下所示:
String s1 = "你好";String s2 = newString(s1.getBytes("GB2312"), "ISO-8859-1");41、日期和时间:
1)如何取得年月日、小时分钟秒?
2)如何取得从1970年1月1日0时0分0秒到现在的毫秒数?
3)如何取得某月的最后一天?
4)如何格式化日期?
答:操作方法如下所示:
1)创建java.util.Calendar 实例,调用其get()方法传入不同的参数即可获得参数所对应的值
2)以下方法均可获得该毫秒数:
Calendar.getInstance().getTimeInMillis(); System.currentTimeMillis(); //何问起hovertree.com
3)示例代码如下:
Calendar time = Calendar.getInstance(); time.getActualMaximum(Calendar.DAY_OF_MONTH); //何问起hovertree.com
4)利用java.text.DataFormat 的子类(如SimpleDateFormat类)中的format(Date)方法可将日期格式化。
42、打印昨天的当前时刻。
답변:
public class YesterdayCurrent { public static void main(String[] args){ Calendar cal = Calendar.getInstance(); cal.add(Calendar.DATE, -1); System.out.println(cal.getTime()); } } //何问起hovertree.com43、比较一下Java 和JavaSciprt。
答: JavaScript 与Java是两个公司开发的不同的两个产品。Java 是原Sun 公司推出的面向对象的程序设计语言,特别适合于互联网应用程序开发;而JavaScript是Netscape公司的产品,为了扩展Netscape浏览器的功能而开发的一种可以嵌入Web页面中运行的基于对象和事件驱动的解释性语言,它的前身是LiveScript;而Java 的前身是Oak语言。
下面对两种语言间的异同作如下比较:
1)基于对象和面向对象:Java是一种真正的面向对象的语言,即使是开发简单的程序,必须设计对象;JavaScript是种脚本语言,它可以用来制作与网络无关的,与用户交互作用的复杂软件。它是一种基于对象(Object-Based)和事件驱动(Event-Driven)的编程语言。因而它本身提供了非常丰富的内部对象供设计人员使用;
2)解释和编译:Java 的源代码在执行之前,必须经过编译;JavaScript 是一种解释性编程语言,其源代码不需经过编译,由浏览器解释执行;
3)强类型变量和类型弱变量:Java采用强类型变量检查,即所有变量在编译之前必须作声明;JavaScript中变量声明,采用其弱类型。即变量在使用前不需作声明,而是解释器在运行时检查其数据类型;
4)代码格式不一样。
补充:上面列出的四点是原来所谓的标准答案中给出的。其实Java和JavaScript最重要的区别是一个是静态语言,一个是动态语言。目前的编程语言的发展趋势是函数式语言和动态语言。在Java中类(class)是一等公民,而JavaScript中函数(function)是一等公民。对于这种问题,在面试时还是用自己的语言回答会更加靠谱。
44、什么时候用assert?
答: assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。一般来说,assertion用于保证程序最基本、关键的正确性。assertion检查通常在开发和测试时开启。为了提高性能,在软件发布后, assertion检查通常是关闭的。在实现中,断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为true;如果表达式计算为false,那么系统会报告一个AssertionError。
断言用于调试目的:
assert(a > 0); // throws an AssertionError if a <= 0
断言可以有两种形式:
assert Expression1;
assert Expression1 : Expression2 ;
Expression1 应该总是产生一个布尔值。
Expression2 可以是得出一个值的任意表达式;这个值用于生成显示更多调试信息的字符串消息。
断言在默认情况下是禁用的,要在编译时启用断言,需使用source 1.4 标记:
javac -source 1.4 Test.java
要在运行时启用断言,可使用-enableassertions 或者-ea 标记。
要在运行时选择禁用断言,可使用-da 或者-disableassertions 标记。
要在系统类中启用断言,可使用-esa 或者-dsa 标记。还可以在包的基础上启用或者禁用断言。可以在预计正常情况下不会到达的任何位置上放置断言。断言可以用于验证传递给私有方法的参数。不过,断言不应该用于验证传递给公有方法的参数,因为不管是否启用了断言,公有方法都必须检查其参数。不过,既可以在公有方法中,也可以在非公有方法中利用断言测试后置条件。另外,断言不应该以任何方式改变程序的状态。
45、Error 和Exception 有什么区别?
答: Error 表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题;比如内存溢出,不可能指望程序能处理这样的情况;Exception 表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况。
补充: 2005年摩托罗拉的面试中曾经问过这么一个问题“If a process reports a stack overflow run-time error, what's the most possible cause?”,给了四个选项a. lack of memory; b. write on an invalid memory space; c. recursive function calling; d. array index out of boundary. Java程序在运行时也可能会遭遇StackOverflowError,这是一个错误无法恢复,只能重新修改代码了,这个面试题的答案是c。如果写了不能迅速收敛的递归,则很有可能引发栈溢出的错误,如下所示:
package com.lovo; public class StackOverflowErrorTest { public static void main(String[] args) { main(null); } } //何问起hovertree.com因此,用递归编写程序时一定要牢记两点:1. 递归公式;2. 收敛条件(什么时候就不再递归而是回溯了)。
46、try{}里有一个return语句,那么紧跟在这个try后的finally{}里的code会不会被执行,什么时候被执行,在return前还是后?
答:会执行,在方法返回调用者前执行。Java允许在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是记录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,这会对程序造成很大的困扰,C#中就从语法上规定不能做这样的事。
47、Java 语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用?
答: Java 通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java 中,每个异常都是一个对象,它是Throwable 类或其子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。Java 的异常处理是通过5 个关键词来实现的:try、catch、throw、throws和finally。一般情况下是用try来执行一段程序,如果出现异常,系统会抛出(throw)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺省处理器来处理;try用来指定一块预防所有“异常”的程序;catch 子句紧跟在try块后面,用来指定你想要捕捉的“异常”的类型;throw 语句用来明确地抛出一个“异常”;throws用来标明一个成员函数可能抛出的各种“异常”;finally 为确保一段代码不管发生什么“异常”都被执行一段代码;可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部写另一个try语句保护其他代码。每当遇到一个try 语句,“异常”的框架就放到栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种“异常”进行处理,栈就会展开,直到遇到有处理这种“异常”的try 语句。
48、运行时异常与受检异常有何异同?
答:异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计得没有问题通常就不会发生。受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发。Java编译器要求方法必须声明抛出可能发生的受检异常,但是并不要求必须声明抛出未被捕获的运行时异常。异常和继承一样,是面向对象程序设计中经常被滥用的东西,神作《Effective Java》中对异常的使用给出了以下指导原则:
不要将异常处理用于正常的控制流(设计良好的API不应该强迫它的调用者为了正常的控制流而使用异常)
对可以恢复的情况使用受检异常,对编程错误使用运行时异常避免不必要的使用受检异常(可以通过一些状态检测手段来避免异常的发生)
优先使用标准的异常每个方法抛出的异常都要有文档保持异常的原子性不要在catch中忽略掉捕获到的异常
49、列出一些你常见的运行时异常?
답변:
ArithmeticException(算术异常)
ClassCastException (类转换异常)
IllegalArgumentException (非法参数异常)
IndexOutOfBoundsException (下表越界异常)
NullPointerException (空指针异常)
SecurityException (安全异常)
50、final, finally, finalize 的区别?
答: final:修饰符(关键字)有三种用法:如果一个类被声明为final,意味着它不能再派生出新的子类,即不能被继承,因此它和abstract是反义词。将变量声明为final,可以保证它们在使用中不被改变,被声明为final 的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改。被声明为final 的方法也同样只能使用,不能在子类中被重写。finally:通常放在try…catch的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。finalize:Object类中定义的方法,Java中允许使用finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize() 方法可以整理系统资源或者执行其他清理工作。
以上就是本文的全部内容,希望对大家参加Java面试有所帮助,也希望大家多多支持武林网。