1 static關鍵字
1:如果沒有static會怎樣?
1:定義Person類
1:姓名、年齡、國籍,說話行為
2:多個構造,重載形式展現
2:中國人的國籍都是确定的
1:國籍可以進行顯示初始化
class Person {
String name;
int age;
String gender;
String country = "CN";
Person() {
}
Person(String name, int age, String gender, String country) {
this.name = name;
this.age = age;
this.gender = gender;
this.country = country;
}
void speak() {
System.out.println("國籍:" + country + " 姓名:" + name + " 性别:" + gender + " 年齡:" + age + " 哈哈!!!");
}
}
3:new Person 對象
1:分析記憶體
2:每個對象都維護執行個體變量國籍也是。
public class PersonDemo {
public static void main(String[] args) {
Person p1 = new Person("jack", 20, "男");
p1.speak();
Person p2 = new Person("rose", 18, "女");
p2.speak();
}
}
4:記憶體分析
1:棧,堆、共享區
2:Demo.class加載近共享區
2.1 Demo類的main方法進棧
2.2 Person p1=new Person();
2.2.1 Person.class 加載進方法區
2.2.2 堆記憶體開辟空間,執行個體變量進行預設初始化,顯示初始化。
2.2.3 記憶體位址傳給變量p1,棧和堆建立連接配接
2.3 person p2=new Person();
2.3.1 堆記憶體開辟空間,執行個體變量進行預設初始化,顯示初始化。
2.3.2 記憶體位址傳給變量p2,棧和堆建立連接配接
2.4:如果建立多個Person對象發現問題
2.4.1 每個對象都維護有國籍。
5:解決問題,記憶體優化
1:為了讓所有Person對象都共享一個country ,可以嘗試将country放入共享區。
1.1 country變量如何放入共享區?對象如何通路?
1.2 使用static
2:static
2.1 為了實作對象之間重複屬性的資料共享
3:static使用
3.1 主要用于修飾類的成員
3.1.1成員變量
3.1.1 非靜态成員變量:需要建立對象來通路
3.1.2 靜态成員變量:使用類名直接調用,也可以通過對象通路
public static void main(String[] args) {
//通路靜态成員
//直接通過類名來調用
String country=Person.country;
System.out.println(country);
//通過對象.成員的形式通路
Person p1 = new Person("jack", 20, "男");
p1.country="US";
p1.speak();
}
class Person {
String name;
int age;
String gender;
//static 修飾成員變量
static String country = "CN";
Person() {
}
Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
void speak() {
System.out.println("國籍:" + country + " 姓名:" + name + " 性别:" + gender
+ " 年齡:" + age + " 哈哈!!!");
}
}
2:成員方法
可以使用類名直接調用
1:靜态函數:
1:靜态函數中不能通路非靜态成員變量,隻能通路靜态變量。
2:靜态方法不可以定義this,super關鍵字.
3:因為靜态優先于對象存在.靜态方法中更不可以出現this
2:非靜态函數:非靜态函數中可以通路靜态成員變量
class Person {
String name;
int age;
String gender;
//static 修飾成員變量
static String country = "CN";
Person() {
}
Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
//非靜态方法
void speak() {
//非靜态方法可以通路靜态成員
System.out.println("國籍:" + country );
System.out.println("國籍:" + country + " 姓名:" + name + " 性别:" + gender
+ " 年齡:" + age + " 哈哈!!!");
}
//靜态方法
static void run(){
//靜态方法隻能通路靜态成員變量。
System.out.println("國籍:"+country);
//靜态方法通路非靜态成員變量,編譯報錯。
System.out.println(" 姓名:" + name);
//靜态方法中不可以出現this,編譯報錯
this.speak();
}
}
2:細節:
1:靜态函數中不能使用非靜态變量
2:非靜态函數可以通路靜态變量
3:為什麼靜态函數中不能通路非靜态成員
1:static修飾的成員在共享區中。優先于對象存在
2:驗證
1:使用靜态代碼塊驗證
1:靜态代碼塊
static{
靜态代碼塊執行語句;
}
1:靜态代碼塊特點
随着類的加載而加載。隻執行一次,優先于主函數。用于給類進行初始化。
public class PersonDemo {
public static void main(String[] args) {
// 通路靜态成員
// 直接通過類名來調用
String country = Person.country;
System.out.println(country);
// 通過對象.成員的形式通路
Person p1 = new Person("jack", 20, "男");
p1.country = "US";
p1.speak();
}
}
class Person {
String name;
int age;
String gender;
// static 修飾成員變量
static String country = "CN";
static {
System.out.println("這是靜态代碼塊");
}
{
System.out.println("這是構造代碼塊");
}
Person() {
System.out.println("無參數構造");
}
Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
System.out.println(" 有參數構造");
}
// 非靜态方法
void speak() {
// 非靜态方法可以通路靜态成員
System.out.println("國籍:" + country);
System.out.println("國籍:" + country + " 姓名:" + name + " 性别:" + gender
+ " 年齡:" + age + " 哈哈!!!");
// 非靜态方法可以調用靜态方法。
run();
}
// 靜态方法
static void run() {
// 靜态方法隻能通路靜态成員變量。
System.out.println("國籍:" + country);
}
}
4:static特點
1 随着類的加載而加載,靜态會随着類的加載而加載,随着類的消失而消失。說明它的生命周期很長。
2 優先于對象存在。–>靜态是先存在,對象是後存在。
3 被所有執行個體(對象)所共享。
4 可以直接被類名調用
5:靜态變量(類變量)和執行個體變量的差別:
1存放位置
1:類變量随着類的加載而加載存在于方法區中.
2:執行個體變量随着對象的建立而存在于堆記憶體中.
2生命周期
1:類變量生命周期最長,随着類的消失而消失.
2:執行個體變量生命周期随着對象的消失而消失.
6:靜态優缺點
1: 優點:對對象的共享資料進行單獨空間的存儲,節省空間 例如Person 都有
國籍。該資料可以共享可以被類名調
2:缺點:生命周期過長
通路出現局限性。(靜态隻能通路靜态)
7: 什麼時候定義靜态變量
1:靜态變量(類變量)當對象中出現共享資料
例如:學生的學校名稱。學校名稱可以共享
對象的資料要定義為非靜态的存放在對記憶體中(學生的姓名,學生的年齡)
8:什麼時候定義靜态函數
如果功能内部沒有通路到非靜态資料(對象的特有資料。那麼該功能就可以定義為靜态)
9:靜态的應用
自定義數組工具類
/*
定義數組工具類
1:定義一個周遊數組的函數
2:定義一個求數組和的功能函數 1. 周遊 2. 兩兩相加
3:定義一個擷取數組最大值的功能函數
4:定義一個擷取數組最大值角标的功能函數
5:定義一個傳回指定數在指定數組中包含的角标的功能函數
6:定義一個可以用于排序int數組的函數
1:冒泡
2:選擇
定義自己的工具類
*/
class Arrays {
private Arrays() {
}
// 1:定義一個周遊數組的函數
public static void print(int[] arr) {
for (int x = 0; x < arr.length; x++) {
if (x != (arr.length - 1)) {
System.out.print(arr[x] + ",");
} else {
System.out.print(arr[x]);
}
}
}
// 2:定義一個求數組和的功能函數
public static int getSum(int[] arr) {
int sum = 0;
for (int x = 0; x < arr.length; x++) {
sum += arr[x];
}
return sum;
}
// 3:定義一個擷取數組最大值的功能函數
public static int getMax(int[] arr) {
int max = 0;
for (int x = 0; x < arr.length; x++) {
if (arr[max] < arr[x]) {
max = x;
}
}
return arr[max];
}
// 4:定義一個擷取數組最大值角标的功能函數
public static int getIndexMax(int[] arr) {
int max = 0;
for (int x = 0; x < arr.length; x++) {
if (arr[max] < arr[x]) {
max = x;
}
}
return max;
}
// 5:定義一個傳回 指定數在指定數組中包含的角标的功能函數
public static int getIndex(int[] arr, int src) {
int index = -1;
for (int x = 0; x < arr.length; x++) {
if (arr[x] == src) {
index = x;
}
}
return index;
}
// 冒泡
public static void test(int[] arr) {
for (int x = 0; x < arr.length - 1; x++) {
if (arr[x] > arr[x + 1]) {
int temp = arr[x + 1];
arr[x + 1] = arr[x];
arr[x] = temp;
}
}
}
// 選擇排序
public static void selectSort(int[] arr) {
for (int x = 0; x < arr.length - 1; x++) {
for (int y = 1 + x; y < arr.length; y++) {
if (arr[x] > arr[y]) {
int temp = arr[y];
arr[y] = arr[x];
arr[x] = temp;
}
}
}
}
// 7:定義一個可以将整數數組進行反序的功能函數。
public static void reverseSort(int[] arr) {
int start = 0;
int end = arr.length - 1;
for (int x = 0; x < arr.length; x++) {
if (start < end) {
int tem = arr[start];
arr[start] = arr[end];
arr[end] = tem;
}
start++;
end--;
}
}
// 折半查找
public static int halfSearch(int key, int[] arr) {
int min = 0;
int max = arr.length - 1;
int mid = 0;
while (min < max) {
mid = (min + max) / 2;
if (key > arr[mid]) {
min = mid + 1;
} else if (key < arr[mid]) {
max = mid - 1;
} else {
return mid;
}
}
return -1;
}
}
class Demo6 {
public static void main(String[] args) {
int[] arr = { 3, 4, 5, 2, 3, 7, 4 };
Arrays.print(arr);
System.out.println();
Arrays.selectSort(arr);
Arrays.print(arr);
}
}
練習:統計建立對象的人數
class Person
{
public String name;
public int age;
static public long all_count;
public Person(){
all_count++;
}
public Person( String name , int age ){
all_count++;
this.name = name;
this.age = age;
}
// 統計人數的函數
public long getCount(){
return all_count;
}
// 應該具備找同齡人的功能
public boolean isSameAge( Person p1 ){
return this.age == p1.age;
}
}
class Demo9
{
public static void main(String[] args)
{
Person p1 = new Person( "jame" , 34 );
Person p2 = new Person( "lucy" , 34 );
Person p3 = new Person( "lili" , 34 );
Person p4 = new Person();
System.out.println( p1.getCount() + " " + p2.getCount() + " " + p3.getCount() );
System.out.println( p1.isSameAge( p2 ) );
System.out.println( p1.isSameAge( p3 ) );
}
}
1.1 main方法詳解
主函數是靜态的
public static void main(String[] args){
}
主函數是什麼:主函數是一個特殊的函數,作為程式的入口,可以被jvm識别。
主函數的定義:
public :代表該函數的通路權限是最大的。
static :代表主函數随着類的加載,就已經存在了。
void: 主函數沒有具體的傳回值
main : 不是關鍵字,是一個特殊的單詞可以被jvm識别。
(String[] args) 函數的參數,參數類型是一個數組,該數組中的元素是字元串。字元串類型的數組。
主函數的格式是固定的:jvm能夠識别
jvm在調用函數是,傳入的是new String[0];
可以在dos視窗中執行 java Demo5 hello world 給類Demo5的main方法傳遞2個參數,參數與參數之間通過空格隔開。
class Demo5 {
public static void main(String[] args) {
// 擷取String[] args 數組長度
System.out.println(args.length);
// 變量args數組
for (int x = 0; x < args.length; x++) {
System.out.println(args[x]);
}
}
}
class MainTest {
public static void main(String[] args) {
// 字元串數組
String[] arr = { "good", "study", "java" };
// 調用Demo5類的main方法,傳遞參數。
Demo5.main(arr);
}
}
2 單例設計模式
一些人總結出來用來解決特定問題的固定的解決方案。
解決一個類在記憶體中隻存在一個對象,想要保證對象的唯一。
1 為了避免其他程式過多的建立該類對象。禁止其他程式建立該類對象。
2 為了其他程式可以通路該類對象,在本類中自定義一個對象。
3 友善其他程式對自定義類的對象的通路,對外提供一些通路方式。
代碼:
1将構造函數私有化
2在類中建立一個私有的本類對象
3提供一個用類名調用的公有方法擷取該對象。
class Single {
private static Single s = new Single(); // 惡漢式
private Single() {
}
public static Single getInstance() {
return s;
}
}
class Single2 {
private static Single2 s = null; // 懶漢
private Single2() {
}
public static Single2 getInstance() {
if (s == null) {
s = new Single2();
}
return s;
}
}
3 繼承
3.1 類和類之間的常見關系。
1:既然繼承是描述類和類之間的關系,就需要先來了解類和類之間的常見關系
3.1.1 現實生活的整體與部分
舉例說明
1:現實生活
1:學生 是人
2:狗 是動物
3:球隊 包含 球員 整體與部分的關系,部分可以删除和增加
4:筆記本包含 cpu 整體與部分的關系,部分不可以删除和增加
5:航母編隊 包含(航母 護衛艦 驅逐艦 艦載機 核潛艇)
3.1.2 java中的類與類關系
java中的類關系
1:is a 關系 (學生是人)
2:has a 整體與部分
class Person{
String name;
int age;
Address add;
Person(){
}
Person(String name,int age,Address add){
this.name=name;
this.age=age;
this.add=add;
}
void speak(){
System.out.println("姓名:"+name+" 年齡:"+age+" "+add.print());
}
}
class Address{
String country;
String city;
String street;
Address(){
}
Address(String country,String city,String street){
this.country=country;
this.city=city;
this.street=street;
}
String print(){
return "位址:"+country+" "+"城市:"+city+" 街道;"+street;
}
}
class Demo3{
public static void main(String[] args){
Address add=new Address("中國","廣州","棠東東路");
Person p=new Person("jack",27,add);
p.speak();
System.out.println();
}
}
3.2 繼承
1:描述一個學生類
1:姓名年齡學号屬性,學習的方法
2:描述一個勞工類
1:姓名年齡工号屬性,工作的方法
3:描述一個人類
1:姓名年齡屬性,說話的方法。
4:發現學生類和人類天生有着聯系,學生和勞工都是人。是以人有的屬性和行為學生和勞工都會有。出現類代碼重複
class Person {
String name;
int age;
// 靜态變量(類變量)對象和對象之間的代碼重複使用靜态變量
static String country = "CN";
Person() {
}
void speak() {
System.out.println(name + ":哈哈,我是人!!!");
}
}
// 讓學生類和人類産生關系,發現學生is a 人,就可以使用繼承
class Student {
String name;
int age;
Student() {
}
void study() {
System.out.println("姓名:" + name + "年紀:" + age + ":好好學習");
}
}
class Worker {
String name;
int age;
void work() {
System.out.println(name + ":好好工作,好好掙錢。");
}
}
class Demo1 {
public static void main(String[] args) {
Student s = new Student();
s.name = "jack";
s.age = 20;
s.study();
Worker w = new Worker();
w.name = "rose";
w.work();
}
}
5:問題:
1:如果沒有繼承,出現類和類的關系無法描述
2:如果沒有繼承,類和類之間有關系會出現類和類的描述代碼的重複。
3.3 繼承特點
1:描述類和類之間的關系
2:降低類和類之間的重複代碼
1:降低對象和對象之間的代碼重複使用靜态變量
2:降低類和類之間的代碼重複使用就繼承
3.4 extends關鍵字
繼承使用extends關鍵字實作
1:發現學生是人,勞工是人。顯然屬于is a 的關系,is a就是繼承。
2:誰繼承誰?
學生繼承人,發現學生裡的成員變量,姓名和年齡,人裡邊也都進行了定義。有重 複代碼将學生類的重複代碼注釋掉,建立學生類對象,仍然可以擷取到注釋的成員。這就是因為繼承的關系,學生類(子類)繼承了人類(父類)的部分
class Person {
String name;
int age;
// 靜态變量(類變量)對象和對象之間的代碼重複使用靜态變量
static String country = "CN";
Person() {
}
void speak() {
System.out.println(name + ":哈哈,我是人!!!");
}
}
// 讓學生類和人類産生關系,發現學生is a 人,就可以使用繼承
class Student extends Person {
Student() {
}
void study() {
System.out.println("姓名:" + name + "年紀:" + age + ":好好學習");
}
}
class Worker extends Person {
void work() {
System.out.println(name + ":好好工作,好好掙錢。");
}
}
class Demo1 {
public static void main(String[] args) {
Student stu = new Student();
stu.name = "jack";
stu.age = 20;
stu.study();
stu.speak();
System.out.println(stu.country);
System.out.println(Student.country);
Worker worker = new Worker();
worker.name = "rose";
System.out.println(worker.country);
worker.work();
worker.speak();
System.out.println();
}
}
繼承細節;
1:類名的設定,被繼承的類稱之為父類(基類),繼承的類稱之為子類
2:子類并不能繼承父類中所有的成員
1:父類定義完整的成員 靜态成員,非靜态,構造方法。靜态變量和靜态方
法都可以通過子類名.父類靜态成員的形式調用成功。
2:所有的私有成員不能繼承,private修飾的成員。
3:構造函數不能被繼承
3:如何使用繼承
1:不要為了使用繼承而繼承。勞工和學生都有共性的成員,不要為了節省代
碼,讓勞工繼承學生。
/*
如何使用繼承:驗證是否有 is a 的關系
例如:學生是人, 小狗是動物
注意:不要為了使用某些功能而繼承,java隻支援單繼承
*/
class DK {
void Ip4S() {
System.out.println("好玩");
}
}
class BGir extends DK {
}
class Demo {
public static void main(String[] args) {
new BGir().Ip4S();
}
}
3.5 super關鍵字
1:定義Father(父類)類
1:成員變量int x=1;
2:構造方法無參的和有參的,有輸出語句
2:定義Son類extends Father類
1:成員變量int y=1;
2:構造方法無參和有參的。有輸出語句
1:this.y=y+x;
3:建立Son類對象
Son son=new Son(3);
System.out.println(son.y); //4
class Father {
int x = 1;
Father() {
System.out.println("這是父類無參構造");
}
Father(int x) {
this.x = x;
System.out.println("這是父類有參構造");
}
void speak() {
System.out.println("我是父親");
}
}
class Son extends Father {
int y = 1;
Son() {
System.out.println("這是子類的無參構造");
}
Son(int y) {
this.y = y + x;
System.out.println("這是子類的有參構造");
}
void run() {
super.speak(); // 通路父類的函數
System.out.println("我是兒子");
}
}
class Demo6 {
public static void main(String[] args) {
Son s = new Son(3);
System.out.println(s.y);// 4
}
}
4:子類對象為什麼可以通路父類的成員。
1:this.y=y+x;有一個隐式的super super.x
5:super關鍵字作用
1:主要存在于子類方法中,用于指向子類對象中父類對象。
2:通路父類的屬性
3:通路父類的函數
4:通路父類的構造函數
6:super注意
this和super很像,this指向的是目前對象的調用,super指向的是目前調用對象的父類。Demo類被加載,執行main方法,Son.class加載,發現有父類Father類,于是Father類也加載進記憶體。類加載完畢,建立對象,父類的構造方法會被調用(預設自動無參),然後執行子類相應構造建立了一個子類對象,該子類對象還包含了一個父類對象。該父類對象在子類對象内部。this super隻能在有對象的前提下使用,不能在靜态上下文使用。
2:子類的構造函數預設第一行會預設調用父類無參的構造函數,隐式語句
super();
1:父類無參構造函數不存在,編譯報錯。
Son(int y) {
//super();隐式語句
this.y = y + x;
System.out.println(“這是子類的有參構造”);
}
3:子類顯式調用父類構造函數
在子類構造函數第一行通過super關鍵字調用父類任何構造函數。如果顯式調用父類構造函數,編譯器自動添加的調用父類無參數的構造就消失。構造函數間的調用隻能放在第一行,隻能調用一次。super() 和this()不能同時存在構造函數第一行。
Son(int y) {
super(y);// 子類顯式調用父類構造函數
this.y = y + x;
System.out.println("這是子類的有參構造");
}
Son(int y) {
this(); //不能同時存在構造函數第一行
super(y);
this.y = y + x;
System.out.println("這是子類的有參構造");
}
4:super思考
如果開發者自定義了一個類,沒有顯示的進行類的繼承,那麼該類中成員函數是否可以使用super關健健字?可以使用,繼承了Object類,Object類是所有類的父類。
class Demo7 {
public void print(){
System.out.println(super.toString());
}
public static void main(String[] args){
new Demo7().print();
System.out.println();
}
}
5:繼承練習
7:重寫(Override)
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();
}
}
3:該現象就叫做重寫(覆寫 override)
1: 在繼承中,子類可以定義和父類相同的名稱且參數清單一緻的函數,将這種函數
稱之為函數的重寫.
4:前提
1:必須要有繼承關系
5:特點
1:當子類重寫了父類的函數,那麼子類的對象如果調用該函數,一定調用的是重寫過後的函數。
可以通過super關鍵字進行父類的重寫函數的調用。
2: 繼承可以使得子類增強父類的方法
6:細節
1: 函數名必須相同
2:參數清單必須相同
3: 子類重寫父類的函數的時候,函數的通路權限必須大于等于父類的函數的訪
問權限否則編譯報錯
4:子類重寫父類的函數的時候,傳回值類型必須是父類函數的傳回值類型或該傳回值類型的子類。不能傳回比父類更大的資料類型: 如子類函數傳回值類型是Object
1:定義 A B C 類 B extends A
2:Father類中定義A getA();
3:Son 類中重寫getA(); 方法,嘗試将傳回值修改為B,C ,Object
1:B編譯通過
2:C 編譯失敗 ,沒有繼承關系
3:Object編譯失敗,比父類的傳回值類型更大
class A {
}
class B extends A {
}
class C {
}
class Father {
String name;
void eat() {
System.out.println("吃窩窩");
}
// 定義一個函數,擷取A類的對象,
A getA() {
return new A();
}
}
class Son extends Father {
public void eat() { // 繼承可以使得子類增強父類的方法
System.out.println("來兩杯");
System.out.println("來倆小菜");
super.eat();
System.out.println("來一根");
}
// B類是A類的子類
B getA() {
return new B();
}
}
class Demo8 {
public static void main(String[] args) {
Son s = new Son();
s.eat();
}
}
7:子類對象查找屬性或方法時的順序:
1:原則:就近原則。
如果子類的對象調用方法,預設先使用this進行查找,如果目前對象沒有找到屬性或方法,找目前對象中維護的super關鍵字指向的對象,如果還沒有找到編譯報錯,找到直接調用。
8:重載和重寫的不同
1:重載(overload):
1:前提: 所有的重載函數必須在同一個類中
2:特點:
函數名相同,參數清單不同,與其他的無關(通路控制符、傳回值類型)
3:不同:
個數不同 、 順序不同、 類型不同
2:重寫(override):
1:前提: 繼承
函數名必須相同、參數清單必須相同。
子類的傳回值類型要等于或者小于父類的傳回值
9:重寫練習
描述不同的動物不同的叫法
1:定義動物類
有名字,有吃和叫的方法
2:定義狗繼承動物重寫父類吃和叫的方法
3:定義貓繼承動物重寫父類吃和叫的方法
class Animal{
int x=1;
String name;
void eat(){
System.out.println("吃東西");
}
void shout(){
System.out.println("我是動物");
}
}
class Dog extends Animal{
void eat(){
System.out.println("啃骨頭");
}
void shout(){
System.out.println("旺旺");
}
void eat(String food){
System.out.println("吃:"+food);
}
}
class Cat extends Animal{
void eat(){
System.out.println("吃老鼠");
}
void shout(){
System.out.println("喵喵");
}
}
class Demo9{
public static void main(String[] args){
Dog d=new Dog();
d.shout();
d.eat();
Cat c=new Cat();
c.shout();
c.eat();
System.out.println();
}
}
3.6 instanceof 關鍵字
1:快速示範instanceof
Person p=new Person();
System.out.println( p instanceof Person);
2:instanceof是什麼?
1:屬于比較運算符:
2:instanceof關鍵字:該關鍵字用來判斷一個對象是否是指定類的對象。
3:用法:
對象 instanceof 類;
該表達式是一個比較運算符,傳回的結果是boolea類型 true|false
注意:使用instanceof關鍵字做判斷時,兩個類之間必須有關系。
3:案例
定義一個功能表函數,根據傳遞進來的對象的做不同的事情,如果是狗讓其看家,如果是貓讓其抓老鼠
2:定義狗類繼承動物類
3:定義貓類繼承動物類
4:定義功能根據傳入的動物,執行具體的功能
5:instanceof好處
1:可以判斷對象是否是某一個類的執行個體
package oop01;
/*
instanceof
比較運算符
檢查是否是類的對象
1:可以判斷對象是否是某一個類的執行個體
用法
對象 instanceof 類;
案例
定義一個功能函數,根據傳遞進來的對象的做不同的事情
如果是狗讓其看家,如果是貓讓其抓老鼠
1:定義動物類
2:定義狗類繼承動物類
3:定義貓類繼承動物類
4:定義功能根據傳入的動物,執行具體的功能
*/
class Animal {
String name;
void eat() {
System.out.println("吃東西");
}
void shout() {
System.out.println("我是動物");
}
}
class Dog extends Animal {
void eat() {
System.out.println("啃骨頭");
}
void shout() {
System.out.println("旺旺");
}
}
class Cat extends Animal {
void eat() {
System.out.println("吃老鼠");
}
void shout() {
System.out.println("喵喵");
}
}
class Demo11 {
public static void main(String[] args) {
Demo11 d = new Demo11();
// 對象 instanceof 類;
System.out.println(d instanceof Demo11);
d.doSomething(new Dog());
d.doSomething(new Cat());
}
// 定義一個功能函數,根據傳遞進來的對象的做不同的事情
// 如果是狗讓其看家,如果是貓讓其抓老鼠
// 對象 instanceof 類;
void doSomething(Animal a) {
if (a instanceof Dog) {
a.eat();
a.shout();
System.out.println("小狗看家");
} else if (a instanceof Cat) {
a.eat();
a.shout();
System.out.println("抓老鼠");
}
}
}
練習:
byte[] bs = new byte[] { 1, 2, 3 };
int[] is = new int[] { 1, 2, 3 };
String[] ss = new String[] { “jack”, “lucy”, “lili” };
System.out.println(bs instanceof byte[]); // true
System.out.println(is instanceof int[]); // true
System.out.println(ss instanceof String[]); // true
// System.out.println(bs instanceof int[]); // 不可轉換的類型
3.7 final關鍵字
1:定義靜态方法求圓的面積
2:定義靜态方法求圓的周長
3:發現方法中有重複的代碼,就是PI,圓周率。
1:如果需要提高計算精度,就需要修改每個方法中圓周率。
4:描述一個變量
1:方法都是靜态的,靜态隻能通路靜态,是以變量也定義為靜态的。
public static double PI=3.14;
1:如果定義為public後,新的問題,類名.PI=300; 改變了PI的值。
2:修改為private,修改為private後進行了封裝,需要getset公共通路方法。
3:現有的知識不能解決這樣的問題了。可以使用final
class Demo12 {
public static final double PI = 3.14; // 靜态常量
public static double getArea(double r) {
return PI * r * r;
}
public static double getLength(double r) {
return PI * r * 2;
}
public static void main(String[] args) {
// Demo12.PI=300; 無法為最終變量 PI 指定值
System.out.println(Demo12.PI);
}
}
5:使用final
1:final關鍵字主要用于修飾類、類成員、方法、以及方法的形參。
2:final修飾成員屬性:
1:說明該成員屬性是常量,不能被修改。
public static final double PI=3.14;
1:public :通路權限最大
2:static :記憶體中隻有一份
3:final :是一個常量
4:常量名大寫
5:必須初指派。
2:使用類名.成員。修改該成員的值,報錯。--常量不能被修改
1:基本資料類型,final使值不變
2:對象引用,final使其引用恒定不變,無法讓其指向一個新的對象,但是對象自身卻可以被修改。
3:該關鍵字一般和static關鍵字結合使用
1:常量可以優先加載,不必等到建立對象的時候再初始化。
4:final和static可以互換位置
5:常量一般被修飾為final
3:fianl修飾類:
1:該類是最終類,不能被繼承。
1:将父類加final修飾,子類繼承,就會報錯。
2:檢視api文檔發現String類是final的。Integer類也是final的
1:為了防止代碼功能被重寫
2:該類沒有必要進行擴充
4:final修飾方法:
1:該方法是最終方法,不能被重寫
2:當一個類被繼承,那麼所有的非私有函數都将被繼承,如果函數不想被子類繼承并重寫可以将該函數final修飾
3:當一個類中的函數都被修飾為final時,可以将類定義為final的。
class Father2{
final void eat(){
System.out.println("eating....");
}
}
class Son2 extends Father2{
//該方法是最終方法,不能被重寫
void eat(){
System.out.println("eating....");
}
}
class Demo12 {
public static void main(String[] args) {
// Demo12.PI=300; 無法為最終變量 PI 指定值
System.out.println(Demo12.PI);
Son2 s=new Son2();
s.eat();
}
5:final關鍵字修飾形參
1:當形參被修飾為final,那麼該形參所屬的方法中不能被篡改。
2: 項目中主要用于一些隻用來周遊未知資料的函數。将未知變量聲明為final的。增強資料的安全性。
class Demo14 {
public static void main(String[] args) {
System.out.println();
String[] arr = { "think in java", "java就業教程", "java核心技術" };
print(arr);
}
// 該方法,列印書名。
public static void print(final String[] arr) {
//arr = null; ,無法重新指派
for (int x = 0; x < arr.length; x++) {
System.out.println(arr[x]);
}
}
}
10:思考
為什麼子類一定要通路父類的構造函數呢
1:子類繼承了父類的屬性,如果要使用父類的屬性必須初始化,建立子類對象,必須先初始化父類屬性
必須調用父類的構造方法。
2:為什麼調用父類無參的構造函數
設計java語言之時,隻知道編譯器會預設添加無參的構造函數,有參的無法确定。
但是可以通過super關鍵字顯式調用父類指定構造函數。
3:為什麼super()this()語句要放在構造函數的第一行
子類可能會用到父類的屬性,是以必須先初始化父類。