這里會講到java的面向物件部分:1.類和物件 ;2.類的無參方法和帶參方法;3.物件與封裝;4.繼承;5.多型,有代碼,有注釋,有顏色標注重點,有詳細的步驟,所以對java面向物件部分迷惑的童鞋可以多看看呀,一定會有所識訓的!!!
一、類和物件
1.1 什么是物件:
用來描述客觀事物的一個物體,有一組屬性和方法構成
1.2物件的特征:
屬性:物件具有的各種特征
每個物件的每個屬性都擁有特定值
例如:張浩和李明的年齡、姓名不一樣
方法(能做的事):物件執行的操作
1.3封裝:
物件同時具有屬性和方法兩種特性
物件的屬性和方法通常是被封裝在一起,共同體現事物的特性,二者相輔相成,不能分割
1.4什么是類:
類是模子,定義物件將會擁有的特征(屬性)和行為(方法)
類和物件的關系:
類是多個對像進行綜合抽象的結果,是物體對像的概念模型;而一個物件是一個類的實體類是抽象的概念,僅僅是模板,
物件是一個你能看的著,摸得著的具體物體,類是物件的型別,
1.5定義類:
①定義類名
語法:
訪問修飾符 class 類名稱{
? //省略類的內部具體代碼
}
注意:
訪問修飾符如public、private等是可選的
class是宣告類的關鍵字
按照命名規范,類名首字母大寫
示例:
//定義一個“人”類
public class Person{
//省略類的內部具體代碼
}
②撰寫類的屬性
物件所擁有的特征在類中表示時稱為類的屬性
語法:訪問修飾符 資料型別 屬性名;
注意:訪問修飾符是可選的,除了訪問修飾符外,其他的語法和宣告變數類似
示例:
//創建“人”類,并為“人”類添加相應屬性
public class Person{
public String name;
public String gender;
public int age;
}
③撰寫類的方法
物件執行操作的行為稱為類的方法
語法:
訪問修飾符 回傳型別 方法名稱(引數型別 引數名1,引數型別 引數名2,……){
//……省略方法體代碼
}
注意:訪問修飾符是可選的
回傳型別可以是void,在定義方法時,回傳型別為void時表明沒有回傳值,方法體中不必使用“return”關鍵字回傳具體資料,但是可以使用“return”關鍵字退出方法
回傳型別如果不是“void”,那么在方法體中一定要使用”return“關鍵字回傳對應型別的結果,否則程式會出現編譯錯誤
小括號中的“引數資料型別 引數名1,引數資料型別 引數名2,……“稱為引數串列
當需要在方法執行的時候為方法傳遞引數時才需要引數串列,如果不需要傳遞引數就可以省略,不過小括號不可以省略,傳遞多個引數時,以英文的逗號進行分隔
示例:
//在“人”類中定義方法,描述人作業的行為
public class Person{ //定義人類
public String name; //姓名
public String gender; //性別
public int age; //年齡
//作業的行為
public void work(){
System.out.println(this.name+"作業理念:干活掙錢有飯吃");
}
}
1.6創建和使用物件:
創建物件:
類中的物件可以呼叫類中的成員,如屬性和方法等
語法:類名 物件名 = new 類名();
注意:new是關鍵字;左邊的類名為物件的資料型別;右邊的類名() 稱為類的構造方法
示例:
//創建 Person 類的物件
Person person = new Person();
使用物件:
在java中,要參考物件的屬性和方法,需要使用“.“
語法:物件名.屬性 //參考物件的屬性
物件名.方法名() //參考物件的方法
示例:
public static void main(String[] args){
Person person = new Person(); //創建物件
person.name = "韓冰";
person.gender = "女";
person.age = 22;
person.work();
}
1.7面對物件的優點:
提高代碼的可重用性
提高代碼的安全性和可維護性
與人類的思維習慣一致
二、類的無參方法和帶參方法
2.1無參方法:
2.1.1定義類的方法:
語法:
訪問修飾符 回傳值型別 方法名(){
? //方法的主體
}
兩種情況:1有回傳值 2 無回傳值
1.有回傳值:
如果方法具有回傳值,方法中必須使用關鍵字return回傳該值,要回傳的資料型別要和回傳值的型別一樣
語法:return 運算式;
作用:跳出方法,回傳結果
2.無回傳值:
如果方法沒有回傳值,回傳值型別為void
無參的方法表示的就是方法名后面的括號中沒有任何內容
示例:
public class AutoLion {
String color = "黃色";
?
public void run() {
System.out.println("正在以0.1米/秒的速度向前奔跑");
}
public void cry() {
String sound = "大聲吼叫" ;
}
public String robBall() {
String ball = "球";
return ball;
}
}
2.1.2方法的呼叫:
語法:物件名.方法名();
注意:方法是個“黑匣子”,完成某個特定的應用程式功能,并回傳結果
方法呼叫:執行方法中包含的陳述句
本類中方法的呼叫:
本類中的方法呼叫,我們直接撰寫方法名();即可

非本類中方法的呼叫:
如果呼叫的是非本類中的方法,需要先創建物件,然后用物件名.方法名(); 呼叫

方法呼叫小結:
方法之間允許相互呼叫,不需要知道方法的具體實作,實作重用,提高效率

2.1.3全域變數和區域變數:
全域變數:宣告在類以內方法以外
區域變數:宣告在方法以內
含義:變數宣告的位置決定變數作用域;變數作用域確定可在程式中按變數名訪問該變數的區域

示例:
public class AutoLion{
//變數1,2,3為全域變數 AutoLion類的方法,其他類的方法都可用
變數1型別 變數1;
變數2型別 變數2;
變數3型別 變數3;
public 回傳型別 方法1(){
//變數4為區域變數 僅方法1可用
變數4型別 變數4;
}
public 回傳型別 方法2(){
//變數5為區域變數 僅方法2可用
變數5型別 變數5;
}
全域變數和區域變數的區別:
1.作用域不同:
區域變數的作用域僅限于定義它的方法
成員變數的作用域在整個類內部都是可見的
2.初始值不同:
java會給全域變數一個初始值
java不會給區域變數賦予初始值
注意:
在同一個方法中,不允許有同名的區域變數
在不同方法中,可以有同名的區域變數
在同一個類中,全域變數和區域變數同名時,區域變數具有更高的優先級
全域變數和區域變數是可以重名,但是在使用的時候按照就近原則
public class Bian{
int a = 10;
public void a(){
int a = 20;
}
public void b(){
System.out.println(a);
}
public static void main(String[] args) {
Bian bian = new Bian();
bian.b(); //結果是10
}
}
public class Bian{
int a;
public void a(){
int a = 20;
}
public void b(){
System.out.println(a);
}
public static void main(String[] args) {
Bian bian = new Bian();
bian.b(); //結果是0
}
}
?
public class Bian{
int a;
public void a(){
int b;
}
public void b(){
System.out.println(b); //會報錯 因為b是區域變數,不會自動給初始值
}
public static void main(String[] args) {
Bian bian = new Bian();
bian.b();
}
}
2.2帶參方法:
2.2.1定義帶引數的方法:
語法:
<訪問修飾符> 1 回傳型別2 <方法名>(<形式引數串列>3) {
? //方法的主體
}
示例:
public class StudentsBiz {
String[ ] names = new String[30];
public void addName(String name){ //一個形式引數
//增加學生姓名
}
public void showNames() { //顯示全部學生姓名
}
呼叫帶引數的方法:
語法:物件名.方法名(引數1, 引數2,……,引數n4)
示例:
public static void main(String[] args) {
StudentsBiz st = new StudentsBiz();
Scanner input = new Scanner(System.in);
for(int i=0;i<5;i++){
System.out.print("請輸入學生姓名:");
String newName = input.next();
st.addName(newName); //實參的型別、數量、順序都要與形參一一對應
}
st.showNames();
}
帶多個引數的方法:
public class Student {
public boolean searchName(int start,int end,String name){
String[] names = {"哈哈","呵呵","嘻嘻","嘿嘿","哼哼"};
boolean find = false;
for(int i=start-1;i<end;i++){
if(names[i].equals(name)){
find = true;
break;
}
}
return find;
}
public static void main(String[] args) {
Student stu = new Student();
if(stu.searchName(1, 5, "哼哼")){ //如果起始位置是1,結束位置是5,要找的"哼哼"在陣列里 //結果就是找到了
System.out.println("找到了");
}else{ //反之沒找到
System.out.println("沒找到");
}
}
}
2.2.2陣列的使用:
public class ArrayTest {
public String max(int[] a){
int max = a[0];
for(int i=0;i<a.length;i++){
if(a[0]<a[i]){
max = a[i];
}
}
String isMax = "最大值是:"+max;
return isMax;
}
@Test
public void test01(){
ArrayTest a = new ArrayTest();
int[] b = {34,12,56,76};
String max = a.max(b);
System.out.println(max);
}
}
2.2.3新創一個型別:
//創建一個學生類
public class Student {
int stuId;
String name;
int age;
public void show(){
System.out.println("學號是:"+stuId+"姓名是:"+name+"年齡是:"+age);
}
}
?public class TestStudent {
Student[] students = new Student[30]; //創建物件陣列,和創建物件一樣;可以使用多次
public void addStu(Student student){
for(int i =0;i<students.length;i++){
if(students[i]==null){
students[i] = student;
break;
}
}
}
public void showStu(){
for(int i =0;i<students.length;i++){
if(students[i]!=null){
students[i].show();
}
}
}
@Test
public void test01(){
Student stu = new Student();
TestStudent testStudent = new TestStudent();
stu.stuId = 188;
stu.age = 19;
stu.name = "張三";
testStudent.addStu(stu);
testStudent.showStu();
}
}
三、物件與封裝
面向物件設計和開發程式的好處:
交流更加流暢;提高設計和開發效率
一個現實世界的問題如何在計算機中描述它們:
1.找出它的種類
2.找出它的屬性
3.找出它的行為
類圖:
1.作用:用于分析和設計“類”
2.優點:直觀、容易理解
3.影像說明:
構造方法:
1.為什么使用構造方法:
由于創建物件使用點的方式給屬性賦值相對繁雜,我們可以使用構造方法來給屬性進行初始化值
2.作用:初始化值;更簡便的賦值
3.語法:訪問修飾符 類名(){}
4.分類:
無參構造方法:
public class Cat {
String name;
int health;
public void show(){
System.out.println(name+health);
}
}
public class TestCat {
public static void main(String[] args) {
Cat cat = new Cat();
cat.show(); //此時的結果是 null 0 因為 name和health都沒有賦值都是初始值
}
}
有參構造方法:
public class Cat {
String name;
int health;
public void show(){
System.out.println(name+health);
}
public Cat(String a,int b){
this.name = a; //this. 后面跟的是類中上面宣告的屬性 "="后面的是有參構造方法括號里的
this.health = b;
}
}
?
public class TestCat {
public static void main(String[] args) {
Cat cat = new Cat("哈哈",18);
cat.show(); //此時的結果是 哈哈 18,因為在上面類中的有參構造方法中讓name和health等于了a和b又在創建物件時給a和b賦了值
}
}?
注意:
在我們創建物件的時候就會呼叫這個構造方法
在我們在類中沒有寫構造方法的時候,系統會默認給我們一個無參構造方法
但是如果類中有了有參的構造方法,則不會自動生成無參構造方法;推薦在寫類的時候將有參和無參構造方法都寫
public class Cat {
String name;
int health;
public void show(){
System.out.println(name+health);
}
}
//在類中沒有有參構造方法時,我們在main方法中創建物件時可以直接創建,此時其實就是無參的構造方法
public class TestCat {
public static void main(String[] args) {
Cat cat = new Cat();
cat.show();
}
}
//當類中有了有參的構造方法時,在創建物件時就需要在括號中添加內容
public class Cat {
String name;
int health;
public void show(){
System.out.println(name+health);
}
public Cat(int a){} //有參的構造方法
}
public class TestCat {
public static void main(String[] args) {
Cat cat = new Cat(); //報錯,因為在類中有了有參的創建物件,如果要修改只能在類中創建一個無參的構造方法,或者在括號中加入有參的構造方法括號中同型別的資料
cat.show();
}
}
在我們執行的時候,new 物件時,物件名后面括號(如:Dog dog = new Dog())里面可以有的引數必須符合類中已宣告的有參構造方法
當類中有無參和有參構造方法時,我們在創建物件的時候如果想呼叫兩個,在創建物件時,物件名要區分開,不能取同樣的名
public class Cat {
String name;
int health;
public void show(){
System.out.println(name+health);
}
public Cat(String a,int b){
this.name = a;
this.health = b;
}
public Cat(){}
}
?
public class TestCat {
public static void main(String[] args) {
Cat cat1 = new Cat("哈哈",18);
cat1.show(); //結果是 哈哈 18
Cat cat2 = new Cat();
cat2.show(); //結果是 null 0 雖然都是呼叫的show方法但是由于構造方法不同結果也是不同的
}
}
this:
1.只能用在方法中;this表示當前類的;不寫也是默認存在的
2.可以修飾屬性(this.屬性名)、方法(this.方法名();)、構造方法(無參:this(); 有參:this(引數);)
在使用this呼叫構造方法的時候必須在構造方法的第一行(構造方法只能在構造方法中呼叫)
3.子類在繼承父類后也可以直接用this來使用父類中的屬性和方法(不是呼叫父類中的方法,因為子類繼承了父類,相當于呼叫本類中的屬性和方法,因此當父類中的方法被重寫后,呼叫父類中的方法需要用super)
多載:
1.方法名相同; 2.引數串列不同(個數,順序,資料型別); 3.在同一個類中;和訪問修飾符以及回傳值型別無關;4.并不只是構造方法有多載,普通方法也有多載;5.兩個構造方法不能同時互相呼叫(行成死回圈)
public void s1(int a,int b){}
public void s1(int c,int d){} //不能形成多載,因為資料型別形同
public void s1(int a,int b){}
public void s2(String a,int b} //不可以多載,因為方法名不同
?public void s1(int a,int b){}
public void s1(String a,int b} //可以多載,因為資料型別不同 和實參名無關
public void s1(int a,int b){}
public int s1(int c,int d){return 1} //可以多載,和訪問修飾符以及回傳值型別無關
為什么需要使用多載:
在使用的時候呼叫方法或者賦值更加的便捷
static:
使用場景:在共用的情況下使用(試想飲水機和水杯的案列)
static:靜態的,是隨著類的加載而加載(靜態的加載完才加載普通的);可以修飾屬性和方法還有代碼塊,表示公用的
使用 static修飾的屬性或者方法,可以使用物件名. 的方式呼叫;也可以使用類名. 的方式呼叫(推薦使用)
static修飾的變數也稱為靜態變數,靜態變數和非靜態變數的區別是:靜態變數被所有物件共享,在記憶體中只有一個副本,它當且僅當在類初次加載時會被初始化,
被static修飾的成員變數屬于類,不屬于某個物件(也就是說:多個物件訪問或修改static修飾的成員變數時,其中一個物件將static成員變數進行了修改,其它的物件的static成員變數值跟著改變,即多個物件共享同一個static成員變數,不是不能改變)
而非靜態變數是物件所擁有的,在創建物件的時候被初始化,存在多個副本,各個物件擁有的副本互不影響,
雖然對于靜態方法來說沒有this,但是我們在非靜態方法中能夠通過this訪問靜態方法成員變數,如下:
public class Test {
static int value = 11;
public static void main(String[] args) {
new Test().printValue();
}
private void printValue() {
int value = 22;
System.out.println(this.value);//輸出的結果是:11
}
}
這里的this表示的是當前物件,那么通過new Test()來呼叫printValue的話,當前物件就是通過new Test()生成的物件,而static變數是被物件所享有的,因此在printValue中的this.value的值毫無疑問是11,在printValue方法內部的value是區域變數,根本不可能與this關聯,所以輸出11,需要記住的是:靜態成員變數雖然獨立于物件,但是不代表不可以通過物件去訪問,所有的靜態方法和靜態變數都可以通過物件訪問(只要權限足夠),
方法呼叫:
普通方法:普通方法是可以呼叫普通方法的,也可以呼叫靜態方法
靜態方法:靜態方法可以呼叫靜態方法,不能呼叫普通方法(因為靜態的加載完才加載普通的)
注意:在靜態方法中不能使用this關鍵字
示例:
public class StartPerson {
String name;
int age;
static String country;
public StartPerson(){}
public StartPerson(String name,int age,String country){
this.name = name;
this.age = age;
this.country = country;
}
public void show(){
System.out.println("姓名是:"+name+",年齡是:"+age+",國籍是:"+country);
}
}
@Test
public void test01(){
StartPerson s1 = new StartPerson("劉德華",40,"中國");
StartPerson s2 = new StartPerson("鳳姐",30,"中國");
StartPerson s3 = new StartPerson("古天樂",39,"美國");
s1.show();
s2.show();
s3.show();
/*結果是姓名是:劉德華,年齡是:40,國籍是:美國
姓名是:鳳姐,年齡是:30,國籍是:美國
姓名是:古天樂,年齡是:39,國籍是:美國
因為國家是static修飾的*/
}
封裝:
為什么使用封裝:
java 封裝,說白了就是將一大坨公共通用的實作邏輯玩意,裝到一個盒子里(class),出入口都在這個盒子上,你要用就將這個盒子拿來用,連接出入口,就能用了,不用就可以直接扔,對你代碼沒什么影響,
對程式員來說,使用封裝的目的:
1.偷懶,辛苦一次,后面都能少敲很多代碼,增強了代碼得復用性
2.簡化代碼,看起來更容易懂
3.隱藏核心實作邏輯代碼,簡化外部邏輯,并且不讓其他人修改,jar 都這么干
4.一對一,一個功能就只為這個功能服務;避免頭發繩子一塊用,導致最后一團糟
在編碼程序中,給屬性賦值的時候,往往會出現一些不符合實際的值,嚴重一些的情況會影響專案的安全,此時就可以使用封裝來解決這樣的問題,沒有使用封裝的時候,用戶可以隨意給屬性賦值
含義:封裝其實就是將屬性給隱藏起來,不讓用戶輕易的去訪問
public class Student {
int age;
public void show(){
System.out.println("年齡是:"+age);
}
}
public class TestStudent {
public static void main(String[] args) {
Student student = new Student();
student.age = -10;
}
}
封裝的步驟:
①將屬性私有化 private
/* 用戶可能不會輸入符合實際的數值
* 為了安全性,選擇將屬性使用private保護起來
* private:私有的,僅本類可見
*/
private int age;
②撰寫setter方法,可以針對用戶輸入的值進行判斷
public void setAge(int age){
if(age>0 && age<100){
this.age = age;
}else{
System.out.println("請輸入符合實際情況的年齡(0—100),默認18歲");
this.age= 18;
}
}
③撰寫getter方法,來獲取值
public int getAge(){
return age;
}
四、繼承
4.1為什么使用繼承:
再多個同種型別中有多個重復的代碼,就會冗余
可以使用繼承避免此種情況出現


4.2概念:
將共同的代碼提取出來放到一個單獨的類中,讓原來的類繼承這個新的類
4.3滿足條件:
子類和父類是is-a關系
注意:
繼承只能是單根繼承(同時只能繼承一個類)
可以間接的去繼承(如a繼承b,b繼承c,a也就間接繼承了c)
4.4關鍵字:
extends
4.5哪些是不能被繼承的:
1.父類的構造方法
2.private 修飾的內容
3.不同包下的 默認修飾符(default)修飾的內容
4.默認修飾符在同包下修飾的內容可以被繼承
4.6 super(寫法與this相同):
可以呼叫 父類中的 屬性,方法,構造方法
如果呼叫構造方法,必須在第一行(構造方法只能在構造方法中呼叫)
4.7 **構造方法執行順序:
在有子父類的情況下,創建物件(子類)中,如果在子類的構造方法中沒有寫呼叫父類的構造方法的話,會默認呼叫父類的無參構造方法
在子類構造方法中如果沒有明示呼叫父類構造方法的話,則默認呼叫父類的無參構造方法
在子類構造方法中如果寫了呼叫父類的具體某個構造方法,則呼叫寫的那個構造方法
子類物件在進行實體化前首先呼叫父類構造方法,再呼叫子類構造方法實體化子類物件,
實際在子類構造方法中,相當于隱含了一個陳述句super(),呼叫父類的無參構造,同時如果父類里沒有提供無參構造,那么這個時候就必須使用super(引數)明確指明要呼叫的父類構造方法,
4.8如何使用繼承:
撰寫父類:
語法:
class Pet{
//公共的屬性和方法
}
撰寫子類,繼承父類:
語法:
class Dog extends1 Pet2{
//子類特有的屬性和方法
}
class Penguin extends Pet{
}
注意:
繼承只能是單繼承,只能同時繼承一個
示例:
//子類
public class Dog extends Pet {
String strain;
public Dog (){
System.out.println("子類構造方法");
super.setHealth(health);
}
public String getStrain() {
return strain;
}
public void setStrain(String strain) {
this.strain = strain;
}
/*public void show(){
System.out.println("我的名字叫"+name+",健康值是"+health+",和主人的親密度是"+love+"我是一只"+strain);
}*/
public void show(){
System.out.println("品種是:"+strain);
}
}
//子類
public class Penguin extends Pet {
String gender;
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public void show(){
System.out.println("性別是"+gender);
}
}
//父類
public class Pet {
String name;
int health;
int love;
public Pet(){
System.out.println("父類構造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public int getLove() {
return love;
}
public void setLove(int love) {
this.love = love;
}
public void show(){
System.out.print("姓名是:"+name+",健康值是:"+health+",好感度是:"+love);
}
}
?
4.9訪問修飾符:
在同一個專案中

4.10方法的重寫:
示例1:
比如,定義Father類
1:姓名,吃飯方法,吃窩窩頭,
2:定義Son類,繼承Father
1:Son類中不定義任何成員,子類創建物件,仍然可以呼叫吃飯的方法,
2:父類的吃飯的方法,Son不愿吃,Son自己定義了吃飯的方法,
1:此時父類中有一個吃飯的方法,子類中有2個吃飯的方法,只是方法體不一樣,
2:一個類中兩個方法一模一樣,是不允許的,
1:編譯運行,執行了子類的方法,
2:使用父類的方法,在子類方法中,使用super.父類方法名,
class Father {
String name;
void eat() {
System.out.println("吃窩窩");
}
}
class Son extends Father {
public void eat() { // 繼承可以使得子類增強父類的方法
System.out.println("來倆小菜");
System.out.println("來兩杯");
System.out.println("吃香喝辣");
System.out.println("來一根");
}
}
?
class Demo8 {
public static void main(String[] args) {
Son s = new Son();
//執行子類的方法
s.eat();
}
}
?
定義:
該現象就叫做重寫(覆寫 override)
在繼承中,子類可以定義和父類相同的名稱并且引數串列一致的方法,將這種函式稱之為方法的重寫
前提:
必須存在有繼承關系
特點:
當子類重寫了父類的方法,那么子類的物件如果呼叫該方法,一定呼叫的是重寫過后的方法,可以通過super關鍵字進行父類的重寫方法的呼叫
繼承可以使得子類增強父類的方法
**細節:
方法名必須相同
引數串列必須相同
子類重寫父類的方法的時候,方法的訪問權限必須大于等于父類的方法的訪問權限否則會編譯報錯
子類重寫父類的方法的時候,回傳值型別必須是父類方法的回傳值型別或該回傳值型別的子類,不能回傳比父類更大的資料型別,如子類方法的回傳值型別是object
拋出的例外不能大于父類
***示例2:
public void test01(){
Student stu1= new Student("張三",4,55);
Student stu2 = new Student("張三",4,55);
boolean i = (stu1.equals(stu2));
System.out.println(i); //stu1和stu2是同一人但是結果是false 這時候就需要重寫equals方法
//等于是在Student 類里寫了一個equals方法
}
?
public boolean equals(Object obj) {
//比較地址值 地址值如果一樣別的就不用看了
if(this==obj){
return true;
}
//先判斷傳進來的obj是否和Student為同一個物件,用instanceof 來判斷
if(obj instanceof Student){
Student i = (Student)obj; //如果不一樣,強轉,類似把int型別的轉為double型別
//看obj里面的內容是否和比較的物件內容是否一樣,如果一樣為true
if(this.id==i.id &&this.name==i.name&&this.score==i.score){
return true;
}
}
return false;
}
abstract:
抽象的,可以修飾方法和類
抽象方法沒有方法體(大括號:{}),抽象方法一定要在抽象類中,但是抽象類中不一定有抽象方法
抽象方法需要被子類都繼承實作,如果子類沒有重寫父類中的抽象方法的話則這個類也需要是抽象類,其方法再由其子類重寫
抽象類不能被實體化
重點:
final和abstract,private和abstract,static和abstract,這些是不能放在一起的修飾符,因為abstract修飾的方法是必須在其子類中實作(覆寫),才能以多型方式呼叫,以上修飾符在修飾方法時其子類都覆寫不了這個方法,final是不可以覆寫,private是不能夠繼承到子類,所以也就不能覆寫,static是可以覆寫的,但是在呼叫時會呼叫編譯時型別的方法,因為呼叫的是父類的方法,而父類的方法又是抽象的方法,又不能夠呼叫,所以上的修飾符不能放在一起,
final:
修飾的類不能被其它類繼承
修飾的方法不能被重寫
修飾的屬性不能被修改
***經典例題:
class A{
public A()
{
System.out.println("1.A類的構造方法");
}
{
System.out.println("2.A類的構造塊");
}
static{
System.out.println("3.A類的靜態方法");
}
}
public class B extends A{
public B()
{
System.out.println("4.B類的構造方法");
}
{
System.out.println("5.B類的構造塊");
}
static{
System.out.println("6.B類的靜態方法");
}
public static void main(String[] args)
{
System.out.println("7.start......");
new B();
new B();
System.out.println("8.end.....");
}
}
主類中的靜態塊優先于主方法執行,所以6應該在7前面執行,但是B類繼承于A類,所以先執行A類的靜態塊3,所以進主方法前的執行順序為:3 6
進主方法后執行7,new B()之后應先執行A的構造方法然后執行B的構造方法,但由于A類和B類均有構造塊,構造塊又優先于構造方法執行即 2 1(A的構造家族) 5 4(B的構造家族),有多少個物件,構造家族就執行幾次,題目中有兩個物件 所以執行順序為:3 6 7 2 1 5 4 2 1 5 4 8(如果main方法重新建一個類執行順序是7 3 6 2 1 5 4 2 1 5 4 8)
五、多型
5.1什么是多型:
所謂多型就是指程式中定義的參考變數所指向的具體型別和通過該參考變數發出的方法呼叫在編程時并不確定,而是在程式運行期間才確定,即一個參考變數倒底會指向哪個類的實體物件,該參考變數發出的方法呼叫到底是哪個類中實作的方法,必須在由程式運行期間才能決定,
因為在程式運行時才確定具體的類,這樣,不用修改源程式代碼,就可以讓參考變數系結到各種不同的類實作上,從而導致該參考呼叫的具體方法隨之改變,即不修改程式代碼就可以改變程式運行時所系結的具體代碼,讓程式可以選擇多個運行狀態,這就是多型性,
比如你是一個酒神,對酒情有獨鐘,某榷訓家發現桌上有幾個杯子里面都裝了白酒,從外面看我們是不可能知道這是些什么酒,只有喝了之后才能夠猜出來是何種酒,你一喝,這是劍南春、再喝這是五糧液、再喝這是酒鬼酒….在這里我們可以描述成如下:
? 酒 a = 劍南春
? 酒 b = 五糧液
? 酒 c = 酒鬼酒
? …
? 這里所表現的的就是多型,劍南春、五糧液、酒鬼酒都是酒的子類,我們只是通過酒這一個父類就能夠參考不同的子類,這就是多型——我們只有在運行的時候才會知道參考變數所指向的具體實體物件,
? 誠然,要理解多型我們就必須要明白什么是“向上轉型”,在繼承中我們簡單介紹了向上轉型,這里就在啰嗦下:在上面的喝酒例子中,酒(Win)是父類,劍南春(JNC)、五糧液(WLY)、酒鬼酒(JGJ)是子類,我們定義如下代碼:
? JNC a = new JNC();
? 對于這個代碼我們非常容易理解無非就是實體化了一個劍南春的物件嘛!但是這樣呢?
? Wine a = new JNC();
? 在這里我們這樣理解,這里定義了一個Wine 型別的a,它指向JNC物件實體,由于JNC是繼承與Wine,所以JNC可以自動向上轉型為Wine,所以a是可以指向JNC實體物件的,這樣做存在一個非常大的好處,在繼承中我們知道子類是父類的擴展,它可以提供比父類更加強大的功能,如果我們定義了一個指向子類的父類參考型別,那么它除了能夠參考父類的共性外,還可以使用子類強大的功能,
? 但是向上轉型存在一些缺憾,那就是它必定會導致一些方法和屬性的丟失,而導致我們不能夠獲取它們,所以父型別別的參考可以呼叫父類中定義的所有屬性和方法,對于只存在與子類中的方法和屬性它就望塵莫及了,
5.2使用:
父類的參考指向子類的實體(物件)
指向子類的父類參考由于向上轉型了,它只能訪問父類中擁有的方法和屬性,而對于子類中存在而父類中不存在的方法,該參考是不能使用的,盡管是多載該方法,若子類重寫了父類中的某些方法,在呼叫該些方法的時候,必定是使用子類中定義的這些方法(動態連接、動態呼叫),
? 對于面向物件而已,多型分為編譯時多型和運行時多型,其中編輯時多型是靜態的,主要是指方法的多載,它是根據引數串列的不同來區分不同的函式,通過編輯之后會變成兩個不同的函式,在運行時談不上多型,而運行時多型是動態的,它是通過動態系結來實作的,也就是我們所說的多型性,
5.3語法:
父類名 父類參考 = new 子類類名(); (類似自動型別轉換)
//類名 物件名 = new 類名();
Dog dog = new Dog();
Cat cat = new Cat();
Penguin penguin = new Penguin();
?
//多型
// 父類名 參考 = new 子類類名();
Pet pet = new Dog();
Pet pet = new Cat();
Pet pet = new Penguin();
如果父類和子類中都有同樣的方法,那么我們在多型方式呼叫的時候呼叫執行的是子類中的方法
那么父類中的方法就不方便同一操作,因此我們可以將方法設定成抽象方法(abstract修飾)
示例:
public class Dog extends Pet{
?
private String strain;
?
public String getStrain() {
return strain;
}
?
public void setStrain(String strain) {
this.strain = strain;
}
public void show(){
System.out.println("品種為:"+strain);
}
public void hospital(){
System.out.println("吃藥打針....");
int h=getHealth()+5;
setHealth(h);
}
}
?
public class Penguin extends Pet{
private String sex;
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
/*public void show(){
System.out.println(name+","+health+","+love+","+sex);
}*/
public void show(){
System.out.println(sex);
}
public void hospital(){
System.out.println("吃藥睡覺....");
setHealth(getHealth()+3);
}
}
?
public abstract class Pet {
private String name;
private int health;
private int love;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public int getLove() {
return love;
}
public void setLove(int love) {
this.love = love;
}
public void show(){
System.out.println(name+","+health+","+love);
}
?
public abstract void hospital();
}
?
public class Master {
/**
* 撰寫一個帶dog去醫院的方法
*/
/*public void toHospital(Dog dog){
if(dog.getHealth()<70){
dog.hospital();
}else{
System.out.println("狗狗很健康.....");
}
}
public void toHospital(Penguin pen){
if(pen.getHealth()<80){
pen.hospital();
}else{
System.out.println("企鵝很健康....");
}
}
*/
public void toHospital(Pet pet){
if(pet.getHealth()<80){
pet.hospital();
}else{
System.out.println("寵物很健康....");
}
}
}
?
public class TestPet {
/**
* 多型:
* 同一種事物在不同條件下的不同狀態
*/
@Test
public void test03(){
Master master = new Master();
//Pet pet = new Pet(); 錯誤
//類名 參考 = new 子類();
//編譯看左邊運行看右邊
Pet pet = new Penguin();
pet.setHealth(40);
master.toHospital(pet);
int health = pet.getHealth();
System.out.println(health);
}
多型情況下,關于屬性和方法的訪問總結:
父子和子類具有相同的成員變數時(靜態或非靜態),訪問的都是父類的成員變數,
子類重寫非靜態方法,訪問子類的方法,子類重寫靜態方法,還是訪問父類的方法
多型:同一個物件(事物),在不同時刻體現出來的不同狀態,
***示例:
貓是貓,貓是動物,
水(液體,固體,氣態),
多型的前提:
A:要有繼承關系,
B:要有方法重寫,
其實沒有也是可以的,但是如果沒有這個就沒有意義,
動物 d = new 貓();
d.show();
動物 d = new 狗();
d.show();
C:要有父類參考指向子類物件,
父 f = new 子();
用代碼體現一下多型,
多型中的成員訪問特點:
A:成員變數
編譯看左邊,運行看左邊,
B:構造方法
創建子類物件的時候,訪問父類的構造方法,對父類的資料進行初始化,
C:成員方法
編譯看左邊,運行看右邊,
D:靜態方法
編譯看左邊,運行看左邊,
(靜態和類相關,算不上重寫,所以,訪問還是左邊的)
由于成員方法存在方法重寫,所以它運行看右邊,
***經典例題:
public class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
public class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
public class C extends B{
}
public class D extends B{
}
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
}
}
?
//運行結果
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D
在這里看結果1、2、3還好理解,從4開始就開始糊涂了,對于4來說為什么輸出不是“B and B”呢?
? 首先我們先看一句話:當超類(父類)物件參考變數參考子類物件時,被參考物件的型別而不是參考變數的型別決定了呼叫誰的成員方法,但是這個被呼叫的方法必須是在超類中定義過的,也就是說被子類覆寫的方法,這句話對多型進行了一個概括,其實在繼承鏈中物件方法的呼叫存在一個優先級:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O),
? 分析:從上面的程式中我們可以看出A、B、C、D存在如下關系,
? 首先我們分析5,a2.show(c),a2是A型別的參考變數,所以this就代表了A,a2.show(c),它在A類中找發現沒有找到,于是到A的超類中找(super),由于A沒有超類(Object除外),所以跳到第三級,也就是this.show((super)O),C的超類有B、A,所以(super)O為B、A,this同樣是A,這里在A中找到了show(A obj),同時由于a2是B類的一個參考且B類重寫了show(A obj),因此最侄訓呼叫子類B類的show(A obj)方法,結果也就是B and A,
? 方法已經找到了但是我們這里還是存在一點疑問,我們還是來看這句話:當超類物件參考變數參考子類物件時,被參考物件的型別而不是參考變數的型別決定了呼叫誰的成員方法,但是這個被呼叫的方法必須是在超類中定義過的,也就是說被子類覆寫的方法,這我們用一個例子來說明這句話所代表的含義:a2.show(b);
? 這里a2是參考變數,為A型別,它參考的是B物件,因此按照上面那句話的意思是說有B來決定呼叫誰的方法,所以a2.show(b)應該要呼叫B中的show(B obj),產生的結果應該是“B and B”,但是為什么會與前面的運行結果產生差異呢?這里我們忽略了后面那句話“但是這兒被呼叫的方法必須是在超類中定義過的”,那么show(B obj)在A類中存在嗎?根本就不存在!所以這句話在這里不適用?那么難道是這句話錯誤了?非也!其實這句話還隱含這這句話:它仍然要按照繼承鏈中呼叫方法的優先級來確認,所以它才會在A類中找到show(A obj),同時由于B重寫了該方法所以才會呼叫B類中的方法,否則就會呼叫A類中的方法,
? 所以多型機制遵循的原則概括為:當超類物件參考變數參考子類物件時,被參考物件的型別而不是參考變數的型別決定了呼叫誰的成員方法,但是這個被呼叫的方法必須是在超類中定義過的,也就是說被子類覆寫的方法,但是它仍然要根據繼承鏈中方法呼叫的優先級來確認方法,該優先級為:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O),
什么叫參考:
1、首先,你要明白什么是變數,變數的實質是一小塊記憶體單元,這一小塊記憶體里存盤著變數的值
比如int a = 1, a就是變數的名名,1就是變數的值,
2、而當變數指向一個物件時,這個變數就被稱為參考變數, 比如A a =new A();
a就是參考變數,它指向了一個A物件,也可以說它參考了一個A物件,我們通過操縱這個a來操作A物件, 此時,變數a的值為它所參考物件的地址
六、介面
介面的特性:
介面不可以被實體化
實作類必須實作介面的所有方法(介面中的方法都需要由其子類實作,否則子類需要是抽象類方法再由其子類實作,與抽象類類似)
實作類可以實作多個介面
方法都是默認public abstract修飾的
在介面中宣告的變數都是靜態常量
介面主要是針對方法而言,約束性更加的寬泛
介面可以被多實作,多個介面之間使用逗號隔開
如果一個類中既有繼承又有實作(使用介面叫實作),將繼承寫在前面,實作寫在后面
介面用interface修飾
實作介面用implements
需要滿足的條件:has-a
示例:
/*
* 介面中的方法都是默認public abstract 修飾的
* 介面也是abstract修飾的
*
* 介面是不能創建物件的
* 介面中的方法都需要由其子類實作,否則子類需要是抽象類方法再由其子類實作
* 在介面中宣告的變數都是靜態常量
* 介面可以被多實作,多個介面之間使用逗號隔開
* 如果一個類中既有繼承又有實作,將繼承寫在前面,實作寫在后面
*/
public interface MyInterface {
int num = 10;
public void show();
}
?
interface YouInterface {
public void you();
}
?
class Y extends A implements MyInterface ,YouInterface{
public void show(){
}
public void you(){
}
}
?
class A implements MyInterface{
int num = 10;
public void show(){
}
}
為什么使用介面:
一定程度上彌補了繼承的缺陷,介面對內容的約束更加的寬泛,針對的是是否有這個東西,主要是來宣告標準的
實際程序中,所有方法不可能只由一個人撰寫
介面就是把具有相同功能,但是本身卻沒有任何關系的類的功能抽象出來,然后讓我們自定義具體的實作,看到一本書這樣寫到:“介面就是一份契約,由類實作契約,契約中我撰寫了某些大的方針與前提,而簽了約的類可以具體問題具體分析來實作自己的功能”
介面就是個招牌,
比如說你今年放假出去杭州旅游,玩了一上午,你也有點餓了,突然看到前面有個店子,上面掛著KFC,然后你就知道今天中飯有著落了,
KFC就是介面,我們看到了這個介面,就知道這個店會賣炸雞腿(實作介面),
那么為神馬我們要去定義一個介面涅,這個店可以直接賣炸雞腿啊(直接寫實作方法),是的,這個店可以直接賣炸雞腿,但沒有掛KFC的招牌,我們就不能直接簡單粗暴的沖進去叫服務員給兩個炸雞腿了,
介面和抽象類的比較:
不同點:
抽象類只能是繼承一個類
介面是可以被多個實作
抽象類中可以有抽象方法和普通方法
介面中只能有抽象方法
相同點:
都表示抽象的,都可以被其他類來實作其中的方法
都不能被實體化
都有抽象方法
七、例外
什么是例外:
例外是指在程式運行程序中所發生的不正常的事件,它會中斷正在運行的程式

什么是例外處理:
Java編程語言使用例外處理機制為程式提供了錯誤處理的能力
為什么使用例外:
代碼冗余、程式員要花很多精力去“堵漏洞”、在實際開發中不一定能夠將每一個程式的漏洞都想到并使用if判斷避免
@Test
public void test01(){
System.out.print("請輸入被除數:");
if(tx.hasNextInt()==true){
int num1 = tx.nextInt();
System.out.print("請輸入除數:");
int num2 = tx.nextInt();
if(num2==0){
System.out.println("除數不能為0");
}
System.out.println("商是:"+num1/num2);
}else{
System.out.println("請輸入整形數值");
}
}
*如何使用:
try catch finally throw throws
try:
將可能出現例外的代碼放入try中
catch:
在一段程式中catch可以有多個,來捕獲例外型別,當出現了某種例外就會中斷例外代碼后面的內容轉而執行對應的catch中的內容
*finally:
在程式中一定會被執行的內容,除非是遇到了exit()方法
當程式中有return的時候,會先執行finally中的內容,然后執行return
結論:
1、不管有木有出現例外,finally塊中代碼都會執行;
2、當try和catch中有return時,finally仍然會執行;
3、finally是在return后面的運算式運算后執行的(此時并沒有回傳運算后的值,而是先把要回傳的值保存起來,不管finally中的代碼怎么樣,回傳的值都不會改變,任然是之前保存的值),所以函式回傳值是在finally執行前確定的;
4、finally中最好不要包含return,否則程式會提前退出,回傳值不是try或catch中保存的回傳值,
最終結論:任何執行try 或者catch中的return陳述句之前,都會先執行finally陳述句,如果finally存在的話,? 如果finally中有return陳述句,那么程式就return了,所以finally中的return是一定會被return的,? 編譯器把finally中的return實作為一個warning,
有return的情況下try catch finally的執行順序:
下面是個測驗程式
public class FinallyTest
{
public static void main(String[] args) {
System.out.println(new FinallyTest().test());;
}
?
static int test()
{
int x = 1;
try
{
x++;
return x;
}
finally
{
++x;
}
}
}
結果是2,
分析:
在try陳述句中,在執行return陳述句時,要回傳的結果已經準備好了,就在此時,程式轉到finally執行了,
在轉去之前,try中先把要回傳的結果存放到不同于x的區域變數中去,執行完finally之后,在從中取出回傳結果,
因此,即使finally中對變數x進行了改變,但是不會影響回傳結果,
它應該使用堆疊保存回傳值,
throw:拋出例外
我們直接在程式中寫例外資訊
public class Student {
private String sex;
?
public String getSex() {
return sex;
}
?
public void setSex(String sex) {
/*
* 如果賦值的是男或者女則正常賦值否則給出例外提示
*
*/
if("男".equals(sex) || "女".equals(sex)){
this.sex = sex;
} else{
//拋出例外
try {
throw new Exception("性別賦值不正確");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void show(){
System.out.println("性別是:"+sex);
}
}
throws:宣告例外
在程式中可能有的例外,我們在方法名后宣告,但是這樣并沒有真正處理,只是將例外交給呼叫者去處理了,如果呼叫者不處理依然會出現例外,除非使用try—catch
@Test
public void test04(){
Demo1 d = new Demo1();
try {
d.show();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void show() throws Exception{ //宣告例外
int[] arr = null;
System.out.println(arr[1]);
}
使用try—catch塊捕獲例外分為三種情況:

正常:try中的代碼塊沒有發生例外,跳過catch并向后執行
出現例外:
try中的代碼塊發生例外,匹配catch,進入匹配的catch執行其中的代碼,執行完跳出try—catch并向后執行
例外型別不匹配:
try中的代碼塊發生例外,在catch中沒有找到匹配的例外,程式中斷(除了finally中的代碼,try—catch后的代碼塊也不執行)

*注意:
在使用catch捕獲例外的時候,需要將例外的范圍從小到大(子類的例外寫在上面,父類的例外寫在下面;因為父類的例外范圍大,寫在前面,后面的子類例外就不執行了)
發生例外時按順序逐個匹配
只執行第一個與例外型別匹配的catch陳述句
常見的例外型別:
|
異 常 類 型 |
說 明 |
|
ArrayIndexOutOfBoundsException |
陣列下標越界例外 |
|
ClassCastException |
型別轉換例外 |
|
NullPointerException |
空指標例外 |
|
ArithmeticException |
數學例外 |
|
InputMismatchException |
輸入型別不匹配 |
|
Exception |
例外層次結構的父類 |
|
ClassNotFoundException |
不能加載所需的類 |
|
IllegalArgumentException |
方法接收到非法引數 |
|
NumberFormatException |
數字格式轉換例外,如把"abc"轉換成數字 |
示例:
import org.junit.Test;
import java.util.*;
public class Demo1 {
Scanner tx = new Scanner(System.in);
/**
* Throwable
* - - -Error : 錯誤,是人為造成的,必須解決
* - - - Exception : 例外
* - - - 運行時例外:在運行的時候才會出現的例外,可以暫時不解決
*
* - - - 編譯時例外:寫代碼的同時編譯時候出現的例外,必須解決了才可以繼續向后執行
*
*
*
* 面試題:常見的例外有哪些,并舉例
* ArrayIndexOutOfBoundsException 陣列下標越界例外
* ClassCastException 型別轉換例外
* NullPointerException 空指標例外
* ArithmeticException 數學例外
* InputMismatchException 輸入型別不匹配
*
*/
/**
* InputMismatchException 輸入型別不匹配
* ArithmeticException 數學例外
*/
@Test
public void test03(){
/*int[] arr = new int[2];
System.out.println(arr[2]);*/
/*String str = "tom";
Object obj = str;
int num = (int)obj;
System.out.println(num);
*/
int[] arr = null;
System.out.println(arr[1]);
}
@Test
public void test02(){
try{
//撰寫可能出現例外的代碼
System.out.print("請輸入被除數:");
int num1 = tx.nextInt();
System.out.print("請輸入除數:");
int num2 = tx.nextInt();
System.out.println("商是:"+num1/num2);
}catch(InputMismatchException e){ //捕獲例外代碼,catch可以出現多次
//可以將例外資訊列印出來
//1、列印堆疊中的資訊
System.out.println("111111");
System.exit(0);
e.printStackTrace();
}catch(ArithmeticException e){
//2、在控制臺直接列印例外的資訊
String message = e.getMessage();
System.out.println(message);
}catch(Exception e){
e.printStackTrace();
}finally{
System.out.println("這是除了exit方法之外一定會被執行的內容");
}
System.out.println("程式結束");
}
@Test
public void test01(){
System.out.print("請輸入被除數:");
if(tx.hasNextInt()==true){
int num1 = tx.nextInt();
System.out.print("請輸入除數:");
int num2 = tx.nextInt();
if(num2==0){
System.out.println("除數不能為0");
}
System.out.println("商是:"+num1/num2);
}else{
System.out.println("請輸入整形數值");
}
}
}
自定義例外:
宣告一個類繼承RuntimeException
重寫有參無參構造方法
最后呼叫
public class MyException extends RuntimeException {
public MyException(String message){
super(message);
}
public MyException(){
super();
}
}
呼叫
public void setSex(String sex) {
/*
* 如果賦值的是男或者女則正常賦值否則給出例外提示
*
*/
if("男".equals(sex) || "女".equals(sex)){
this.sex = sex;
} else{
//拋出例外
try {
throw new MyException("性別賦值不正確~~~");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
日志:
如果專案上線了,出現問題怎么辦呢?同城同區的可以安排開發人員去現場查看除錯,如果非同城,派遣作業人員就不便,這個時候就可查閱日志,找到原因然后根據原因解決問題
使用步驟:
1:加入 log4j-1.2.17.jar 將游標放在專案名上新建檔案夾 lib(為了統一管理,以后有類似檔案都放在這個檔案夾中)
2.需要將游標點在檔案上,然后 Build-path add to build path ,才可以成功的加入到專案中

2:加入日志的組態檔
? 在src目錄下新建文本檔案 檔案找不到點other搜索file
? 檔案名后綴名是 .properties

將日志檔案賦值到log4j.properties檔案中
3:使用
在需要記錄日志的類下面導包

然后輸入下面內容
Logger logger = Logger.getLogger(Demo1.class.getName());//Demo1為當前類名
@Test
public void text06(){
try{
System.out.print("請輸入被除數:");
int a = tx.nextInt();
logger.debug("被除數:"+a); //在需要記錄的位置下輸入
System.out.print("請輸入除數:");
int b = tx.nextInt();
logger.debug("除數:"+b);
System.out.println("商是:"+a/b);
logger.debug("商:"+(a/b));
}catch(InputMismatchException e){
e.printStackTrace();
System.out.println("型別");
}catch(ArithmeticException e){
System.out.println(e.getMessage());
System.out.println("數學");
}
}
組態檔說明:
Log4j由三個重要的組件構成:日志資訊的優先級,日志資訊的輸出目的地,
日志資訊的輸出格式,日志資訊的優先級從高到低有ERROR、WARN、 INFO、DEBUG,
分別用來指定這條日志資訊的重要程度;日志資訊的輸出目的地指定了日志將
列印到控制臺還是檔案中;而輸出格式則控制了日志資訊的顯示內容,
?
?
------------------------------------------------
appender 的配置?
------------------------------------------------
org.apache.log4j.ConsoleAppender-----------控制臺
org.apache.log4j.FileAppender--------------檔案
org.apache.log4j.DailyRollingFileAppender--每天產生一個日志檔案
org.apache.log4j.RollingFileAppender-------檔案大小到達指定尺寸的時候產生一個新的檔案
org.apache.log4j.WriterAppender------------將日志資訊以流格式發送到任意指定的地方
------------------------------------------------
記錄器的配置
-------------------------------------------------
log4j.rootLogger = [ level ] , appenderName, appenderName, …
| |---追加器名
|
|
----日志的級別
------------------------------------------------
layout 的配置?
------------------------------------------------
org.apache.log4j.HTMLLayout(以HTML表格形式布局),
org.apache.log4j.PatternLayout(可以靈活地指定布局模式),
org.apache.log4j.SimpleLayout(包含日志資訊的級別和資訊字串),
org.apache.log4j.TTCCLayout(包含日志產生的時間、執行緒、類別等等資訊)
---------------------------------------------------------------------------
Log4J采用類似C語言中的printf函式的列印格式格式化日志資訊,列印引數如下:
---------------------------------------------------------------------------
%p 輸出優先級,即DEBUG,INFO,WARN,ERROR,FATAL
%r 輸出自應用啟動到輸出該log資訊耗費的毫秒數
%c 輸出所屬的類目,通常就是所在類的全名
%t 輸出產生該日志事件的執行緒名
%n 輸出一個回車換行符,Windows平臺為“rn”,Unix平臺為“n”
%d 輸出日志時間點的日期或時間,默認格式為ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},輸出類似:2002年10月18日 22:10:28,921
%l 輸出日志事件的發生位置,包括類目名、發生的執行緒,以及在代碼中的行數,舉例:Testlog4.main(TestLog4.java:10)
%m 輸出代碼中指定的訊息
好啦,到目前為止,關于java的面向物件部分,基本寫的差不多啦,還剩下物件參考
與物件的區別、多型性理解、向上轉型和向下轉型、堆疊和堆等關于java面向物件的提高的
知識,會放在另一篇講,我們另一篇見,幫助到你們的話,可以點贊關注收藏一波O(∩_∩)O~!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/73368.html
標籤:Java
上一篇:Java并發編程(07):Fork/Join框架機制詳解
下一篇:java面向物件(提高篇)



