Java 內部類詳解及其練習
學習心得
一、專業課
1、內部類
1.內部類
1.1 是指在一個外部類的內部再定義一個類,類名不需要和文件夾相同
1.2內部類可以是靜態static的,也可用public,default,protected和private修飾(而外部類只能使用 public和default)
1.3注意:內部類是一個編譯時的概念,一旦編譯成功,就會成為完全不同的兩類。對於一個名為outer的外部類和其內部定義的名為 inner的內部類。編譯完成後出現outer.class和 outer$inner.class兩類。所以內部類的成員變數/方法名可以和外部類的相同
2、成員內部類
成員內部類,就是作為外部類的成員,可以直接使用外部類的所有成員和方法,即使是
3.區域性內部類
區域性內部類,是指內部類定義在方法和作用域內
4.匿名內部類沒有引用名的內部類
publicclass InnerClass {
publicstatic void main(String[] args) {
/*
* 1.內部類
* 1.1 是指在一個外部類的內部再定義一個類,類名不需要和文件夾相同
* 1.2 內部類可以是靜態static的,也可用 public,default,protected和private修飾
* (而外部類只能使用public和default)
* 1.3
* 對於一個名為outer的外部類和其內部定義的名為 inner的內部類。
* 編譯完成後出現outer.class和outer$inner.class兩類。所以內部類的成員變數/方法名可以和外部類的相同。
*/
Bodybody = new Body();
Body.Heartheart = new Body().new Heart(); //非靜態內部類時的宣告方式
// Body.Heartheart2 = new Body.Heart(); // 注意靜態內部類的生成(不需要Body後的())
heart.thump();
body.walk();
Sleepsleep = new Sleep();
sleep.sleep("yes",new YesOrNo() { //匿名內部類
@Override
publicvoid no() {
//TODO Auto-generated method stub
System.out.println("no,最多再睡三分鐘");
}
@Override
publicvoid yes() {
//TODO Auto-generated method stub
System.out.println("yes,多睡六分鐘");
}
});
}
}
classBody{
staticprivate int weigth;
publicvoid walk() {
inti = 2;
System.out.println("walk");
classShoes{ //成員方法中,成員內部類,只能用 default(不能寫出)final同i一樣
publicvoid wear() {
System.out.println("blackshoes"+i); //jdk1.8開始i才不需要是final常量
}
}
//區域性內部類相當於一個屬性,需要在內部初始化,外部無法呼叫
newShoes().wear();
}
publicstatic void sWalk() {
System.out.println("staticwalk");
}
/*
* 成員內部類,就是作為外部類的成員,可以直接使用外部類的所有成員和方法,即使是private的。
* 同時外部類要訪問內部類的所有成員變數/方法,則需要通過內部類的物件來獲取
*/
/*static*/class Heart{ //成員位置上的內部類,成員內部類(可以是static)
intrate;
/*
* 成員內部類(非靜態)不能含有static的變數和方法。因為成員內部類需要先建立了外部類,才能建立它自己的
* 靜態變數需要在一個靜態環境中,也就是內部類需要時靜態的
*/
// staticint r;
/**
* java類載入順序,首先載入類,執行static變數初始化,接下來執行物件的建立,如果我們要執行程式碼中的變數intr 初始化,
* 那麼必須先執行載入外部類,再載入內部類,最後初始化靜態變數a,問題就出在載入內部類上面,
* 不妨把內部類看成外部類的非靜態成員,它的初始化必須在外部類物件建立後以後進行,要載入內部類必須在例項化外部類之後完成,
* java虛擬機器要求所有的靜態變數必須在物件建立之前完成,這樣便產生了矛盾
* 而java常量放在記憶體中常量池,它的機制與變數是不同的,編譯時,載入常量是不需要載入類的,所以就沒有上訴那種矛盾
*/
staticfinal int r = 2;
publicvoid thump() {
System.out.println("heartthumping");
System.out.println(weigth+Body.this.weigth);//訪問外部類屬性可以用外部類.this.屬性名來呼叫
sWalk();
walk();
classT{} //厲害了,居然還可以巢狀,但還是饒了別人把
}
}
}
classSleep{
classHeart{} //不同類下可以有重名的內部類
publicvoid sleep(String or,YesOrNo yesOrNo) {
if("yes".equals(or)) {
yesOrNo.yes();
}else{
yesOrNo.no();
}
}
interfaceYesOrNo{
voidyes();
voidno();
}
}
二、小組PK
1.我方題目
1.以下程式能否執行
如果不能請指出錯在那裡,
如果可以請輸出程式結果:
classB extends A {
publicB() {
System.out.println("B");
}
publicvoid show(B obj) {System.out.println("B and B"); }
publicvoid show(A obj) {System.out.println("B and A");}
}
classC extends B {
Dd = new D();
classD {
D(){
show(newA());
}
}
}
publicclass A {
publicvoid show(A obj) {System.out.println("A and A");}
publicstatic void main(String[] args) {
Cc = new C();
c.show(newB());
}
}
B //建立C的例項,呼叫C的無參構造方法,C的預設構造方法第一條語句隱含它的父類B的無參構造方法,所以第一個輸出B
Band A //D()呼叫show(newA()),newA()是陷阱,因為並沒有呼叫A的show方法。所以是呼叫D的show()方法。
//D及它的外部類C中都沒有定義show方法,所以找到C的父類B中,根據引數對應輸出B and A
B //c.show(newB()),呼叫publicB(),輸出B
Band B //根據引數找到 Band B
2.請找出下面程式的錯誤,可能有幾處(請在錯誤語句後面打星*):
publicclass Animal {
classAnima{
System.out.println("animal"); *//輸出語句不能寫在這個位置,應該寫在方法或者語句塊中
}
publicstatic void main(String[] args) {
Integeri = -2;
Catcat = new Animal(); *//向下轉型需要將強制型別轉換
Animaldog = new Dog();
if(cat instanceof Dog) { *//eclipse編譯器會報編譯錯誤
System.out.println("cat");
}
}
}
classCat extends Animal{}
classDog extends Animal{}
3.請找出下面程式的錯誤,可能有幾處(請在錯誤語句後面打星*):
publicclass Test {
inta;
voidTest(int a){ //這不是建構函式
this.a=a++;
}
publicstatic void main(String[] args) {
finalTest t = new Test(5);* //沒有帶參的建構函式
}
privateclass A{
Staticint a = 10; *//Static 這個不是靜態關鍵字
System.out.println(a); *
public void getA(final Test t){
t= new Test(6); *
System.out.println(t.a);
}
}
}
4.程式是否能夠執行,如果能執行結果是什麼?不能請說明理由
注意輸出格式
publicclass Question {
publicstatic void main(String[] args) {
Aa = new B();
System.out.println(a.method1('c'));
a.fun(); ***
}
}
classA{
staticint i;
inta = 10;
{
i= method1('d');
}
public int method1(char c){
if(c> 0){
returni + a;
}
return0;
}
staticvoid method(){
i++;
}
}
classB extends A{
public void fun(){
System.out.println(i);
A.method();
}
}
程式不能執行,在帶*出物件a不能呼叫fun()方法,因為父類A裡面沒有fun方法,所以A類的引用找不到fun方法,報錯。
5.分別用惡漢式和 懶漢式 實現單例設計模式 intage 方法名自擬
classSingle{
privateint age;
privateSingle() {
super();
}
publicint getAge() {
returnage;
}
publicvoid setAge(int age) {
this.age= age;
}
privatestatic Single s = new Single();
publicstatic Single getInstances(){
returns;
}
}
classSingle2{
privateint age;
privateSingle2() {
super();
}
publicint getAge() {
returnage;
}
publicvoid setAge(int age) {
this.age= age;
}
privatestatic Single2 s = null;
publicsynchronized static Single2 getInstances(){
if(s== null){
s= new Single2();
}
returns;
}
}
2、對方題目
1、publicclass Demo03 extends S{
publicfinal void mb_method(int i){
System.out.println(i);
}
publicstatic void main(String[] args) {
//TODO Auto-generated method stub
Demo03demo01 = new Demo03();
demo01.mb_method();
demo01.mb_method(2);
}
}
classS{
publicfinal void mb_method(){
System.out.print("1");
}
}
A.程式可以通過編譯,並正常執行輸出“12”
B.程式可以通過編譯,但無法正常執行
C.程式無法通過編譯,因為方法呼叫有問題
D.程式無法通過編譯,因為具有final屬性的方法不能被覆蓋
A
2、父類為Person,子類為Student,父類中有一個使用private修飾的屬性school,若student的物件想要修改該屬性的值為“新東方”並且獲取該屬性打印出來,該如何實現?請完整下列程式程式。
classPerson{
privateString school;
}