前言
java是一門面向對象的語言,而對象是類的一個實例,有行爲和狀態。類是一個模板,它描述一類對象的行爲和狀態。所以本文將從一個類作爲模板的角度,從結構上對類這個抽象概念進行分析描述。
模板圖
說明:圖中標紅的屬於類這個概念,由於匿名內部類,比較特殊(它與局部類很相似,不同的是它沒有類名,如果某個局部類你只需要用一次,就可以採用局部內部類來定義它)所以在模板圖中就不做展示,關於抽象類會在抽象方法中做說明。
1.成員變量
1.1常量
常量是指在程序的整個運行過程中值保持不變的量,常量值又稱爲字面常量,它是通過數據直接表示的。常量不同於常量值,它可以在程序中用符號來代替常量值使用,因此在使用前必須先定義。常量與變量類似也需要初始化,即在聲明常量的同時要賦予一個初始值。常量一旦初始化就不可以被修改。
它的聲明格式爲:
final dataType variableName = value;
其中,final 是定義常量的關鍵字,dataType 指明常量的數據類型,variableName 是變量的名稱,value 是初始值.,例如:
final int i =5;
1.2靜態常量
由final和static共同修飾的爲靜態常量。例如:
final static int i=6;
靜態常量和常量的區別:
static+final
- 靜態常量,編譯期常量,編譯時就確定值。
- 放於方法區中的靜態常量池。
- 在編譯階段存入調用類的常量池中
- 如果調用此常量的類不是定義常量的類,那麼不會初始化定義常量的類,因爲在編譯階段通過常量傳播優化,已經將常量存到調用類的常量池中了
final
- 常量,類加載時確定或者更靠後。
- 當用final作用於類的成員變量時,成員變量(注意是類的成員變量,局部變量只需要保證在使用之前被初始化賦值即可)必須在定義時或者構造器中進行初始化賦值
- 對於一個final變量,如果是基本數據類型的變量,則其數值一旦在初始化之後便不能更改;
- 如果是引用類型的變量,則在對其初始化之後便不能再讓其指向另一個對象。但是它指向的對象的內容是可變的
1.3.普通變量
在Java語言中,所有的變量在使用前必須聲明。聲明變量的基本格式如下:
type identifier [ = value][, identifier [= value] ...] ;
格式說明:type爲Java數據類型。identifier是變量名。可以使用逗號隔開來聲明多個同類型變量。如:
class Demo{
int = 5;
}
1.4靜態成員變量
靜態成員變量:也叫類變量,獨立於方法之外的變量,用 static 修飾。
注意:
static修飾的成員變量屬於類,不屬於某個對象。即:多個對象訪問或修改static修飾的成員變量時,其中一個對象將static成員變量進行了修改,其它的對象的static成員變量值跟着改變,即多個對象共享同一個static成員變量。
舉例如下:創建狗類對象時,默認給值 爲1,之後依次被修改。具體代碼及運行結果如下
public class Demo {
public static void main(String[] args) {
//創建對象dog1
Dog dog1 = new Dog();
//調用test 方法
dog1.test();
//直接通過類名調用,並修改
Dog.age = 2;
System.out.println("類名調用修改後的age:"+Dog.age);
//通過對象修改
int age = dog1.age;
age = 3;
System.out.println("對象調用修改後的age:"+age);
}
}
//創建狗類
class Dog{
static int age = 1;
public void test(){
System.out.println("狗類中的age:"+age);
}
}
輸出結果爲:
2.代碼塊
2.1靜態代碼塊
static代碼塊指的是static{}
包裹的代碼塊,且靜態代碼只執行一次,可以通過Class.forName("classPath")
的方式喚醒代碼的static代碼塊,但是也執行一次。
class Demo{
//屬性
static int age;
//靜態代碼塊
//靜態信息初始化(預先加載資源)
static {
age = 1;
System.out.println("靜態代碼塊");
}
}
2.2構造代碼塊
使用{}
包裹的代碼區域,這裏的代碼區域特指位於class{}
下面的而不是存在於其他type method(){}
這類函數下面的代碼區域
class Demo{
{
System.out.println("構造代碼塊");
}
}
3.構造方法
構造方法,是一種特殊的方法。主要用來在創建對象時初始化對象, 即爲對象成員變量賦初始值,總與new運算符一起使用在創建對象的語句中。特別的一個類可以有多個構造函數 ,可根據其參數個數的不同或參數類型的不同來區分它們,即構造函數的重載。
語法規則:
1.方法名必須與類名相同
2.無返回值類型,也不能用void修飾(有任何返回值類型的方法都不是構造方法)
3.可以指定參數,也可以不指定參數;分爲有參構造方法和無參構造方法
構造方法的特點:
1.當沒有指定構造方法時,系統會自動添加無參的構造方法。
2.構造方法可以重載:方法名相同,但參數不同的多個方法,調用時會自動根據不同的參數選擇相應的方法。
3.構造方法是不被繼承的
4.當我們手動的指定了構造方法時,無論是有參的還是無參的,系統都將不會再添加無參的構造方法。
例如,創建一個Person 類,添加age,name 屬性,並添加無參構造及有參構造
class Person{
//屬性
int age;
String name;
//無參構造
public Person() {
}
//一個參數構造
public Person(int age) {
this.age = age;
}
//多個參數的構造
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
4.內部類
4.1成員內部類
首先內部類的概念是:在Java中,可以將一個類定義在另一個類裏面或者一個方法裏面,這樣的類稱爲內部類。
成員內部類:在方法外類內定義類。(具體細節及注意事項等在下面代碼中註明)
/**
* 成員內部類
*/
public class InnerDemo2 {
public static void main(String[] args) {
/**
* 方法一
*/
//創建成員內部類對象
Outer2.Inner2 inner2 = new Outer2().in;
//對象調用內部類方法
inner2.n();
/**
* 方法二
*/
Outer2.Inner2 inner21 = new Outer2().new Inner2();
//對象調用內部類方法
inner2.n();
}
}
//外部類
class Outer2{
//屬性
static int i =1;
//非靜態屬性,可以通過對象調用
Inner2 in = new Inner2();
/**
* 成員內部類:可以當成一個大的屬性
* 1.可以定義所有的非靜態信息(屬性,方法)及靜態常量
* 2.可以被4個訪問權限修飾符修飾及final、abstract
* 3.可以獲取外部類所有信息
*/
class Inner2{
int x=2;
static final int xx =3;
//報錯 static 不能修飾
//static int xxx =4;
public void n(){
System.out.println(i);
m();
}
}
//方法
public void m(){}
}
4.2靜態內部類
靜態內部類:成員內部類加上static(具體細節及注意事項等在下面代碼中註明)
/**
*靜態內部類
*/
public class InnerDemo3 {
public static void main(String[] args) {
//創建靜態內部類對象
Outer3.Inner3 inner3=new Outer3.Inner3();
inner3.n();
}
}
//外部類
class Outer3{
//屬性
static int i=1;
//靜態內部類
//可以定義所有的信息以及靜態常量
//可以進行繼承和實現
//可以被訪問權限修飾符以及final/abstract
//只能獲取外部類的所有靜態信息
static class Inner3 extends Object implements Cloneable{
static final int x=2;
public void n(){
System.out.println(i);
}
}
//方法
public void m(){}
}
5.成員方法
方法的定義:
- 方法是類或對象的行爲特徵的抽象。
- Java中的方法不能獨立存在,所有的方法必須定義在類中。
- 使用 “類名.方法” 或 “對象.方法” 的形式調用。
- 語法格式:
權限修飾符 返回值類型 方法名(參數類型 參數名) {
// 方法體
// 返回值
}
5.1靜態方法
靜態方法:static修飾的方法,從屬於類。最常見的main()方法就是一個靜態方法
public class Demo {
public static void main(String[] args) {
}
}
靜態方法隨着類的加載而加載到方法區的靜態方法區裏,與類同級也叫類方法,通過類名.形式來調用。靜態方法存放在靜態區裏不會被賦予系統默認初始值,當靜態方法被調用時會加載到棧中進行執行(類名.形式--參考如下代碼)。
public class Demo {
public static void main(String[] args) {
//直接通過類名.形式來調用
Dog.eat();
}
}
//創建狗類
class Dog{
static void eat(){
System.out.println("狗吃東西");
}
}
注意事項:
- 靜態方法可以重載
- 靜態方法不能重寫
- 靜態信息(變量、方法。。)可以使用靜態信息,但是不能直接使用非靜態信息
- 非靜態信息可以直接使用靜態信息以及非靜態信息
- this 是非靜態的,靜態方法裏面不能直接使用
5.2普通方法
普通方法:沒有static,final 等關鍵字修飾的方法
- 可以進行方法的重載
- 可以進行方法的重寫
//創建狗類
class Dog{
public void sleep(){
System.out.println("狗在睡覺");
}
}
5.3最終方法
最終方法:被 final 修飾的方法
注意事項:
- 最終方法不能被重寫
- 最終方法可以重載
- 最終類和非最終類都可以包含最終方法
public class demo {
//編寫最終方法add
public final static int add(int a,int b) {
return a+b;
}
}
//此時會報錯“cannot override the final method from demo”
//不能重寫來自demo的最終方法
public class mydemo extends demo{
public static int add(int a,int b) {
return a+b;
}
public static void main(String[] args)
{
int x=10;
int y=2;
System.out.println(add(x,y));
}
}
//非最終類包含最終方法
class demo {
public final static int add(int a,int b) {
return a+b;
}
public static void main(String[] args)
{
int x=20;
int y=5;
System.out.println(x/y);
System.out.println(add(x,y));
}
}
//運行結果:
//4
//25
5.4抽象方法
抽象方法:被關鍵字abstract 修飾的方法
當父類中的某個方法被所有子類進行不同程度的重寫,那麼父類裏的這個方法就沒有實際意義,則捨棄掉方法體,加上 abstract 變成抽象方法(沒有方法體---一定要重寫)。
抽象類
抽象方法所在的類就是抽象類。如果普通類繼承抽象類,那麼需要重寫所有的抽象方法,如果不想重寫,則類需要修改爲抽象類。
注意:
- 抽象類裏不一定含有抽象方法
- 抽象類不能創建對象,否則能調用到抽象方法,就會出現問題(可以定義構造方法,但是不能創建對象)
- 抽象類可以做屬性初始化
- 抽象方法支持重載(重載只和方法名和參數列表有關)
- 抽象方法不可以被private/final/static,抽象方法一定需要重寫
- 抽象類不能被final 修飾,因爲抽象方法一定需要重寫,重寫前提是繼承,最終類沒有子類就不行
- 抽象類的目的主要是爲了延展類繼承結構
/**
* 抽象類:Employee
*/
abstract class Employee
{
//屬性
private String name;
private String address;
private int number;
//抽象方法
public abstract double computePay();
}
5.5方法內部類
方法內部類:方法內定義的類。
注意:
- 方法內部類中可以定義所有的非靜態信息以及靜態常量
- 方法內部類中可以進行正常的繼承和實現
- 方法內部類不能被訪問權限修飾符來修飾,但是可以被final、abstrat 修飾
- 方法內部類可以獲取外部類所有的信息
- 方法內部類只能獲取本方法中的常量
- 方法內部類創建對象需要在本方法中
package com.tedu.inner;
/**
* 方法內部類
*/
public class InnerDemo1 {
public static void main(String[] args) {
//外部類對象調用m()方法,執行創建內部類對象的代碼
new Outer1().m();
}
}
//外部類
/**
* 類只能被public default 修飾
*/
class Outer1{
//屬性
int x = 1;
//方法
public void m(){
/**
* 1.jdk 1.8 開始默認底層加上final
* 2.jdk1.7 及其以前需要強制加上final
*/
int k = 10;
//此處修改k=8 內部類System.out.println(k); 就會報錯
//k=8;
//方法內部類
/**
* 1.可以定義所以非靜態屬性和方法以及[靜態常量]
* 2.可以進行正常的繼承和實現
* 3.不能被訪問權限修飾符修飾,但是可以被final,abstract 修飾
* 4.方法內部類,可以獲取外部類所有的信息
* 5.只能獲取本方法中的常量信息
*/
class Inner1 extends Object implements Cloneable{
int y = 2;
//靜態屬性和方法不行
//靜態區沒有存儲所以
static final int yy=2;
public void mn(){
System.out.println(x);
n();
//只有拿本方法中的變量纔會默認加上final,否則不加,比如上面執行k=8時,就
//不會添加final
System.out.println(k);
//報錯,k 默認是常量不能被改變
//System.out.println(k=1);
}
}
//在本方法中創建內部類實例
Inner1 inner1 = new Inner1();
inner1.mn();
}
public void n(){}
}