JAVA學習筆記
作者:劉先寶
寫作日期:2016.2.23
更新日期:2016.2.25
版本號:2.0
大綱
1.說說JAVA與PHP的變量作用域
2.JAVA繼承中的方法的覆蓋和重載
3,JAVA類的多態
4,JAVA內部類
1,說說JAVA與PHP的變量作用域
因為JAVA是純OOP語言,而PHP是基于OOP語言,所以變量的作用域是不同的。
1.JAVA作用域:
在Java中,變量的作用域分為四個級別:類級、對象實例級、方法級、塊級。
類級變量又稱全局級變量或靜態變量,需要使用static關鍵字修飾。類級變量在類定義后就已經存在,占用內存空間, 可以通過類名來訪問,不需要實例化。
對象實例級變量就是成員變量,實例化后才會分配內存空間,才能訪問。
方法級變量就是在方法內部定義的變量,就是局部變量。
塊級變量就是定義在一個塊內部的變量,變量的生存周期就是這個塊,出了這個塊就消失了,比如if、for 語句的塊。 塊是指由大括號包圍的代碼,例如:
{
int age = 3;
String name =
"www.weixueyuan.net";
// 正確,在塊內部可以訪問 age 和name 變量
System.out.println( name + "已經" + age + "歲了");
}
// 錯誤,在塊外部無法訪問 age 和name 變量
System.out.println( name + "已經" + age + "歲了");
說明:
? 方法內部除了能訪問方法級的變量,還可以訪問類級和實例級的變量。
public class Dog{
static int size=10;
public String str="你好";
public void testTheInner() {
System.out.println(Dog.size);//訪問類級
System.out.println(this.str);//訪問方法級
}
public static void main(String args[]) {
Dog out= new Dog();
out.testTheInner()
}
}
? 塊內部能夠訪問類級、實例級變量,如果塊被包含在方法內部,它還可以訪問方法級的變量。
? 方法級和塊級的變量必須被顯示地初始化,否則不能訪問。
public class Demo{
public static String name = "微學苑"; // 類級變量
public int i; // 對象實例級變量
// 屬性塊,在類初始化屬性時候運行
{
int j = 2;// 塊級變量
}
public void test1() {
int j = 3; // 方法級變量
if(j == 3) {
int k = 5; // 塊級變量
}
// 這里不能訪問塊級變量,塊級變量只能在塊內部訪問
System.out.println("name=" + name+ ", i=" + i + ", j=" + j);
}
public static void main(String[] args) {
// 不創建對象,直接通過類名訪問類級變量
System.out.println(Demo.name);
// 創建對象并訪問它的方法
Demo t = new Demo();
t.test1();
}
}
2.PHP作用域 。
PHP 中的每個變量都有一個針對它的作用域,它是指可以在其中訪問變量(從而訪問它的值)的一個領域。變量的作用域是它們所駐留的頁面。
因此, 如果你定義了$var,頁面余下部分就可以訪問 $var,但是,其它頁面一般不能訪問它(除非使用特殊的變量session,cookie)。但是,當使用你自己定義的函數時,所有這些都將變得不那么 明顯。這些函數具有它們自己的作用域,這意味著在一個函數內使用的變量不能在其外部使用,在一個函數外
部定義的變量不能在其內部使用。
由于這個原因,函數內部的變量可以具有與其外部的變量相同的名稱,但是它們仍然是完全不同的變量,并且具有不同的值。要改變一個函數內的變量的作用域。
?可以使用 global 語句和根據每個值作為參數傳入。 例如:
$var = 20;
class A {
function __construct() {
//do something
}
function init() {
global $var;
echo $var;
}
}
$A = NEW A();
$A->init();
輸出:20;
?常量一旦被聲明將可以在全局可見,也就是說,它們可以函數內外使用,但是這僅僅限于一個頁面之中(包含我們通過include和include_once)包含進來的PHP腳本,
但是在其他的頁面中就不能使用了。例如:
const string = 20;
class A {
function __construct() {
//do something
}
function init() {
echo string;
}
}
$A = NEW A();
$A->init();//輸出20;
?在一個腳本中聲明的全局變量在整個腳本中是可見的,但不是在函數內部,在函數內部的變量如果與全局變量名稱相同,以函數內部的變量為準。
?函數內部使用的變量聲明為全局變量時,其名稱要與全局變量的名稱一致,在這樣的情況下,我們就可以在函數中使用函數外部的全局變量了,這樣就可以避免上一種因為函數內部的變量與外部的全局變量名稱相同而覆蓋了外部變量這樣的情況。
?在函數內部創建并聲明為靜態的變量無法在函數外部可見,但是可以在函數的多次執行過程中保持該值,最常見的情況就是在函數的遞歸執行的過程之中。
function Test(){
static $count = 0;
$count++;
echo $count;
if ($count < 10) {
Test ();
}
$count--;
}
?在函數內部創建的變量對函數來說是本地的,而當函數終止時,該變量也就不存在了。
?PHP中沒有塊作用域的概念。
$str="str" ;
if(1){
$str="string";
}
echo $str
會輸出string,如果有塊作用域的話應該輸出str.
2、繼承中的方法的覆蓋和重載
在java中,變量覆蓋稱為隱藏父類變量,方法稱為重載。
方法覆蓋的原則:
? 覆蓋方法的返回類型、方法名稱、參數列表必須與原方法的相同。
? 覆蓋方法不能比原方法訪問性差(即訪問權限不允許縮小)。
? 覆蓋方法不能比原方法拋出更多的異常。
? 被覆蓋的方法不能是final類型,因為final修飾的方法是無法覆蓋的。
? 被覆蓋的方法不能為private,否則在其子類中只是新定義了一個方法,并沒有對其進行覆蓋。
? 被覆蓋的方法不能為static。如果父類中的方法為靜態的,而子類中的方法不是靜態的,但是兩個方法除了這一點外其他都滿足覆蓋條件,那么會發生編譯錯
誤;反之亦然。即使父類和子類中的方法都是靜態的,并且滿足覆蓋條件,但是仍然不會發生覆蓋,因為靜態方法是在編譯的時候把靜態方法和類的引用類型進行匹 配。
覆蓋和重載的不同:
? 方法覆蓋要求參數列表必須一致,而方法重載要求參數列表必須不一致。
? 方法覆蓋要求返回類型必須一致,方法重載對此沒有要求。
? 方法覆蓋只能用于子類覆蓋父類的方法,方法重載用于同一個類中的所有方法(包括從父類中繼承而來的方法)。
? 方法覆蓋對方法的訪問權限和拋出的異常有特殊的要求,而方法重載在這方面沒有任何限制。
? 父類的一個方法只能被子類覆蓋一次,而一個方法可以在所有的類中可以被重載多次。
class FarClass{
private $myPv;
protected $myVar;
public function myFun(){
...
}
....
}
class SonClass extends FarClass{
private $myPv;
protected $myVar;
public function myFun(){
...
}
...
}
從上面的例子中可以看出, 類的私有變量不會產生覆蓋。原因在于private成員無法繼承下來。對于protected/pulic變量,則會產生覆蓋問題。如果要在子類中訪問父類變量,在java中可能使用super關鍵字,即:
class SonClass{
private $myPv;
protected $myVar;
public function myFun{}
public fuction myFun2{
//下面這名將會拋出一個異常,不能訪問父類私有變量
//var0 = super.myPv;
var1 = super.myVar;
var2 = super.myFun();
}
...
}
PHP中
PHP的parent關鍵詞只能用于調用父類的可繼承方法(protected/public)及可繼承靜態變量,而對于非靜態成員,則會拋出異 常:Fatal error: Access to undeclared static property。如:
class Far{
protected $myVar;
private function Fun1(){}
function Fun2(){}
}
class Son extends Far{
protected $myVar;
funciton Fun2(){
//下面句將會拋出異常,不能訪問父類私有方法。
parent :: Fun1();
//下面會報錯,Fatal error: Access to undeclared static property:
$var = parent :: $myVar;
//這一句正常運行,無論方法是否為靜態方法。
parent :: Fun2();
}
}
如果要訪問父類被覆蓋的變量,通過上面的例子可以看出是不行的,那么,唯一的辦法是在父類中增加一個方法,通過調用父類方法,從而取得被覆蓋的父類變量。
3、JAVA中類的多態。
多態性的一般定義為:同一個操作作用于不同的類的實例,將產生不同的執行結果。在Java中,父類的變量可以引用父類的實例,也可以引用子類的實例。
我們來看例子:
class Father{
public void func1(){
func2();
}
public void func2(){
System.out.println("AAA");
}
}
class Child extends Father{
public void func1(int i){
System.out.println("BBB");
}
public void func2(){
System.out.println("CCC");
}
}
public class PolymorphismTest {
public static void main(String[]args) {
Father child = new Child(); //定義一個父類類型的引用指向一個子類的對象
child.func1();//輸出CCC
child.func1(20)//沒法通過編譯
}
}
上面的程序是個多態的例子。子類Child繼承了父類Father,并重載了父類的func1()方法,重寫了父類的func2()方法。重載后的func1(int i)和func1()不再是同一個方法,由于父類中沒有func1(int i),那么,父類類型的引用child就不能調用func1(int i)方法。而子類重寫了func2()方法,那么父類類型的引用child在調用該方法時將會調用子類中重寫的func2()。 所以對于多態,可以總結它為:
一、使用父類類型的引用指向子類的對象;
二、該引用只能調用父類中定義的方法和變量;(父類類型的引用可以調用父類中定義的所有屬性和方法,而對于子類中定義而父類中沒有的方法,它是無可奈何的, 同時,父類中的一個方法只有在在父類中定義而在子類中沒有重寫的情況下,才可以被父類類型的引用調用;)
三、如果子類中重寫了父類中的一個方法,那么在調用這個方法的時候,將會調用子類中的這個方法;
四、它成立的條件為:要有繼承、要有重寫、父類變量引用子類對象。
從上面的例子可以看出,多態的一個好處是:當子類比較多時,也不需要定義多個變量,可以只定義一個父類類型的變量來引用不同子類的實例。請再看下面的一個例子:
public class Demo {
public static void main(String[] args){
// 借助多態,主人可以給很多動物喂食
Master ma = new Master();
ma.feed(new Animal(), new Food());
ma.feed(new Cat(), new Fish());
ma.feed(new Dog(), new Bone());
}
}
// Animal類及其子類
class Animal{
public void eat(Food f){
System.out.println("我是一個小動物,正在吃" + f.getFood());
}
}
class Cat extends Animal{
public void eat(Food f){
System.out.println("我是一只小貓咪,正在吃" + f.getFood());
}
}
class Dog extends Animal{
public void eat(Food f){
System.out.println("我是一只狗狗,正在吃" + f.getFood());
}
}
// Food及其子類
class Food{
public String getFood(){
return "事物";
}
}
class Fish extends Food{
public String getFood(){
return "魚";
}
}
class Bone extends Food{
public String getFood(){
return "骨頭";
}
}
// Master類
class Master{
public void feed(Animal an, Food f){
an.eat(f);
}
}
運行結果:
我是一個小動物,正在吃事物
我是一只小貓咪,正在吃魚
我是一只狗狗,正在吃骨頭
所以我們可以增加很多的子類,調用相同的方法通過傳遞不同的參數就可以引用不同子類的實例。
PHP通過設計模式的工廠模式可以實現多態應用,下面我引用PHP的工廠模式來說明
例子:
interface people {
function jiehun();
}
class man implements people{
function jiehun() {
echo '送玫瑰,送戒指!<br>';
}
}
class women implements people {
function jiehun() {
echo '穿婚紗!<br>';
}
}
class SimpleFactoty {
static function
createMan($operate) {
if($operate=='man'){
return new man();
} else if($operate=='woman')
return new women();
}
}
$man =SimpleFactoty::createMan('man');
$man->jiehun();//送玫瑰,送戒指!<br>
$man =SimpleFactoty::createMan('women');
$man->jiehun();//穿婚紗!
4,JAVA內部類實例化及分類
在Java 中,允許在一個類(或方法、語句塊)的內部定義另一個類,稱為內部類(InnerClass),有時也稱為嵌套類(Nested Class)。
必須先有外部類的對象才能生成內部類的對象,因為內部類需要訪問外部類中的成員變量,成員變量必須實例化才有意義,外部類要想訪問內部類的成員變量和方法,則需要通過內部類的對象來獲取。例:
public class Outer {
private int size;
public class Inner {
private int counter = 10;
public void doStuff() {
size++;
}
}
public static void main(String args[]) {
Outer outer= new Outer();
Inner inner= outer.new Inner();
inner.doStuff();
System.out.println(outer.size);
System.out.println(inner.counter);
// 編譯錯誤,外部類不能訪問內部類的變量
System.out.println(counter);
}
}
內部類可以是靜態(static)的,可以使用 public、protected 和 private 訪問控制符,而外部類只能使用public,或者默認。
1,成員式內部類
在外部類內部直接定義(不在方法內部或代碼塊內部)的類就是成員式內部類,它可以直接使用外部類的所有變量和方法,即使是private 的。外部類要想訪問內部類的成員變量和方法,則需要通過內部類的對象來獲取。
public class Outer{
private int size;
public class Inner {
public void dostuff() {
size++;
}
}
public void testTheInner() {
Inner in= new Inner();
in.dostuff();
}
}
成員式內部類如同外部類的一個普通成員。
成員式內部類可以使用各種修飾符,包括 public、protected、private、static、final 和abstract,也可以不寫。
若有 static 修飾符,就為類級,否則為對象級。類級可以通過外部類直接訪問,對象級需要先生成外部的對象后才能訪問。
非靜態內部類中不能聲明任何static 成員。
2,局部內部類
局部內部類(Local class)是定義在代碼塊中的類。它們只在定義它們的代碼塊中是可見的。
局部類有幾個重要特性:
僅在定義了它們的代碼塊中是可見的;
可以使用定義它們的代碼塊中的任何局部 final 變量;
局部類不可以是static 的,里邊也不能定義 static 成員;
局部類不可以用public、private、protected 修飾,只能使用缺省的;
局部類可以是abstract 的。
例如:
public class Outer {
public static final int TOTAL_NUMBER = 5;
public int id = 123;
public void func() {
final int age = 15;
String str= "http://www.weixueyuan.net";
classInner {
public void innerTest() {
System.out.println(TOTAL_NUMBER);
System.out.println(id);
// System.out.println(str);不合法,只能訪問本地方法的final變量
System.out.println(age);
}
}
new Inner().innerTest();
}
public static void main(String[] args) {
Outer outer= new Outer();
outer.func();
}
}