匿名類對象 創建的類的對象是匿名的。當我們只需要一次調用類的對象時,我們就可以考慮使用匿名的方式創建類的對象。特點是創建的匿名類的對象只能夠調用一次! package day007; //圓的面積 class circle { double radius; public double getArea ...
匿名類對象
創建的類的對象是匿名的。當我們只需要一次調用類的對象時,我們就可以考慮使用匿名的方式創建類的對象。特點是創建的匿名類的對象只能夠調用一次!
package day007; //圓的面積 class circle { double radius; public double getArea() { // TODO Auto-generated method stub return Math.PI * radius * radius; } public void setRadius(double r){ radius = r; } public double getRadius(){ return radius; } public void show(){ System.out.println("我是一個圓"); } } public class lambda{ public void printArea(circle c, int time){ System.out.println("radius"+"\t"+"area"); for(int i =1;i<= time;i++){ c.setRadius(i); System.out.println(c.getRadius() + "\t" + c.getArea()); } } public static void main(String[] args){ lambda p = new lambda(); circle c = new circle();//新的圓半徑為0 p.printArea(c, 5); new circle().show();//這個對象就是匿名對象,只使用一次後就無法再次調用 } }對象作為參數傳遞
在上面這個例子里,我們使用new circle()直接調用circle的方法。這個對象就是匿名類對象,這個對象產生時,在記憶體堆中開闢記憶體存儲了數據,但是在棧中並沒有相應的變數名指向這塊記憶體地址,那麼我們無法再第二次調用這個匿名類,即我們不可以使用此類再次調用circle類的屬性與方法。
在java虛擬機中,這個匿名類對象很快就被垃圾回收機制收走了,切記,當我們某個類對象只需要使用一次的情況,我們才會考慮使用匿名類對象。
可變個數的行參的方法:
格式:對於方法的形參: 數據類型 ... 形參名;
可變個數的形參的方法與同名的方法之間構成重載;
可變個數的形參在調用時,個數從0開始,到無窮多個都可以。
使用可變多個形參的方法與方法的形參使用數組是一致的。
若方法中存在可變個數的形參,那麼一定要聲明在方法形參的最後。
在一個方法中,最多聲明一個可變個數的形參。
package day007; public class javaArgs { public static void main(String[] args) { // TODO Auto-generated method stub javaArgs jargs = new javaArgs(); jargs.getSum(1,2,3,4); new javaArgs().getSum(123,223); jargs.getSum("求和是", 2,3,5,8); } // public int getSum(int ... args){ public void getSum(int ... args){ int sum = 0; //args使用與數組一致 for(int i = 0; i<args.length;i++){ sum += args[i]; } System.out.println(sum); // return sum; } //重載,可變個數的形參聲明在方法形參的最後 public void getSum(String s,int ... args){ int sum = 0; for(int i = 0; i<args.length;i++){ sum += args[i]; } System.out.println(s + ":"+ sum); } }java的*args的使用
java中形參與實參
形參:方法聲明時,方法小括弧內的參數,實參:調用方法時,實際傳入的參數的值。
我們之前做的兩個值轉換:
package day007; public class TestArgsTransfer { public static void main(String[] args) { // TODO Auto-generated method stub //兩個值轉換 int i = 10; int j = 5; System.out.println("i:" + i + " j:" + j); int temp = i; i = j; j = temp; System.out.println("i:" + i + " j:" + j); } }兩個值交換
然後你可能會想用一個類封裝一個方法完成交換。然後你寫了這樣一個方法。
package day007; public class TestArgsTransfer { public static void main(String[] args) { // TODO Auto-generated method stub //兩個值轉換 int i = 10; int j = 5; //封裝到類方法 TestArgsTransfer tt = new TestArgsTransfer(); System.out.println("i:" + i + " j:" + j); tt.swap(i, j);//將i的值傳遞給m,j的值傳遞給n System.out.println("i:" + i + " j:" + j); } //定義一個方法,交換兩個變數的值 public void swap(int m,int n){ int temp = m; m = n; n = temp; System.out.println("m:" + m + " n:" + n); } }你寫的封裝方法
結果是你的i和j根本就沒有變,為什麼呢?
簡單來說就是i與j是你定義的類屬性,你將i,j作為實參傳到了類方法裡面,類方法swap里的兩個變數發生了位置轉換,但是main中的兩個值並沒有發生任何變化,在記憶體中的表現如上圖,調用swap方法時,會在棧中存兩個swap的局部變數,這兩個變數的值交換了,但是main的變數未發生改變。
那我們要如何做呢。
package day007; public class TestArgsTransfer1 { public static void main(String[] args) { // TODO Auto-generated method stub TestArgsTransfer1 tt = new TestArgsTransfer1(); DataSwap ds = new DataSwap(); System.out.println("ds.i:" + ds.i + " ds.j:" + ds.j); tt.swap(ds); System.out.println(ds); System.out.println("ds.i:" + ds.i + " ds.j:" + ds.j); } //交換元素的值 public void swap(DataSwap d){ int temp = d.i; d.i = d.j; d.j = temp; System.out.println(d);//列印引用變數d的值 } } class DataSwap{ int i = 10; int j = 5; }形參是引用數據類型
這裡swap方法傳入的是一個引用數據類型ds,相當於d與ds一致都指向同一個堆空間,那麼在swap中完成兩個值的交換。
練習一下,下麵代碼的執行結果是什麼:
class Value { int i = 15; } class TestValue { public static void main(String argv[]) { TestValue t = new TestValue(); t.first(); } public void first() { int i = 5; Value v = new Value(); v.i = 25; second(v, i); System.out.println(v.i); } public void second(Value v, int i) { i = 0; v.i = 20; Value val = new Value(); v = val; System.out.println(v.i + " " + i); } }
分析:
第一步,定義了TestValue類,在類的main函數中,生成一個實例t,併在堆中開闢記憶體(0x0001),在棧中定義t指向堆中記憶體0x0001。實例調用實例的first方法。
第二步,在棧中有局部變數i值為5,一個新的變數v,指向堆中新開闢記憶體(0x0011),v的局部變數i值為25,將v與當前局部變數i=5作為實參傳給second方法。
第三步,局部變數i的值改為0,v的局部變數i變為20,定義一個新變數val指向堆中先開闢記憶體(0x0111),second中實參v指向記憶體(0x0111)
第四步,此時列印v.i值為記憶體0x0111中的i,值為15,i為局部空間中的變數i為0,first列印的v.i值為20(實參傳入first,v本身未發生指向的改變)。
面向對象:封裝
我們考慮不讓對象來直接作用屬性,而是通過"對象.方法"的形式,來控制對象對屬性的訪問。實際情況中,對屬性的要求就可以通過方法來體現。
兩種方法:①將類的屬性私有化,②提供公共的方法(setter & getter)來實現調用。
package day007; public class java_private { public static void main(String[] args) { // TODO Auto-generated method stub Animal an = new Animal(); // an.legs = 4;//飄紅 an.setLegs(4); an.getLegs(); } } class Animal{ private String name; private int legs; public void setLegs(int l){ legs = l; } public int getLegs(){ System.out.println(legs); return legs; } }私有封裝
許可權修飾符
構造器
也就是構造方法,但是與python的__init__有相似之處,但是不完全一致。
構造器的作用:①創建對象 ②給創建的對象的屬性賦值(創建對象的話,相當於python中的__new__與__init__的作用)。
1.設計類時,若不顯式聲明類的構造器的話,程式會預設提供一個空參的構造器
預設加()就相當於調用了構造器了,類比python加()後實例化即調用了構造方法。
2.一旦顯式的定義類的構造器,那麼預設的構造器就不再提供。
3.如何聲明類的構造器。格式:許可權修飾符 類名(形參){ }。
4.類的多個構造器之間構成重載。
類對象的屬性賦值的先後順序:①屬性的預設初始化 ②屬性的顯式初始化③通過構造器給屬性初始化 ④通過"對象.方法"的方式給屬性賦值。
package day007; public class init { public static void main(String[] args) { Person p1 = new Person(); System.out.println(p1.getName() + ":" + p1.getAge()); String str = new String("hello"); System.out.println(str); Person p2 = new Person("jeff"); System.out.println(p2.getName()); System.out.println(p2.getAge()); Person p3 = new Person("frank",23); System.out.println("name:" + p3.getName() + " age:" + p3.getAge()); //體會屬性賦值的過程 Person p4 = new Person(); System.out.println("name:" + p4.getName() + " age:" + p4.getAge()); Person p5 = new Person(12); System.out.println("name:" + p5.getName() + " age:" + p5.getAge()); } } class Person{ //屬性 private String name; private int age = 1; //構造器 public Person(String n){ name = n; } public Person(){ // age = 10; // name = "張三"; } public Person(int a){ age = a; } public Person(String n,int a){ name = n; age = a; } //方法 public void setName(String n){ name = n; } public void setAge(int a){ age = a; } public String getName(){ return name; } public int getAge(){ return age; } }構造器
本節代碼托管到我的github:day007。