java學習筆記part3 day01,day02,day03
day01
static關鍵字
靜態成員變量
-
可以修飾成員變量和成員方法,所屬于類
-
static修飾成員變量,表示該成員變量只在內存中存儲一份,可以被共享,修改
-
訪問格式:類名.靜態成員變量
實例成員變量
-
沒有static修飾,存在于每個對象中,所屬于對象
-
訪問格式:對象.實例成員變量
package d1_static;
public class User {
/**
* static修飾的變量,靜態成員變量,內存中只有一份,所屬于類
*/
public static int onlineNumber = 161;
/**
* 實例成員變量,無static修飾,所屬于對象,用對象名訪問
*/
private String name;
private int age;
public static void main(String[] args) {
//1. 類名.靜態成員變量,推薦方式
System.out.println(User.onlineNumber);
//2.對象名.實例成員變量,推薦方式
User u = new User();
u.name = "張三";
u.age = 21;
System.out.println(u.age);
System.out.println(u.name);
u.onlineNumber++;//使用對象名訪問,不推薦
System.out.println(u.onlineNumber);
}
}
靜態成員方法
- static修飾,歸屬于類,建議用類名訪問,也可以用對象訪問
實例成員方法
- 沒有static修飾,只能用對象訪問
package d1_static;
public class Student {
/**
* 實例成員變量,無static修飾,屬于對象
*/
private String name;
/**
* 靜態成員方法,有static修飾,,屬于類??梢员还蚕碓L問,類名和對象名都可以訪問
*/
public static int getMax(int age1, int age2){
return age1 > age2 ? age1 : age2;
}
/**
* 實例方法,屬于對象,只能用對象訪問
*/
public void study(){
System.out.println(name);
}
public static void main(String[] args) {
//1.類名.靜態方法
System.out.println(Student.getMax(4, 6));
System.out.println(getMax(8, 6));//同一個類中,靜態方法可以不寫類名
//對象.實例方法
Student s = new Student();
s.name = "666";
s.study();
//對象.靜態方法,(語法可行,不推薦)
System.out.println(s.getMax(3, 34));
}
}
使用場景
-
表示對象自己的行為的,方法中需要訪問實例成員的,則該方法必須申明實例方法
-
如果該方法是以執行一個公用功能為目的,則可以申明成靜態方法
注意事項
-
靜態方式只能訪問靜態的成員,不可以直接訪問實例成員
-
實例方法可以訪問靜態成員,也可以訪問實例成員
-
靜態方法中不可以出現this關鍵字,this關鍵字代表當前對象
工具類
- 類中都是一些靜態的方法,每個方法都是以完成一個共用的功能為目的,這個類用來給系統開發人員使用
- 提高代碼重用性
- 工具類里都是靜態方法,直接訪問類名就可調用,因此工具類無需創建對象,將工具類的構造器私有
package d2_static_util;
public class Login {
public static void main(String[] args) {
System.out.println(Util.createVerifyCode(5));
}
}
package d2_static_util;
public class Check {
public static void main(String[] args) {
System.out.println(Util.createVerifyCode(9));
}
} return code;
}
}
package d2_static_util;
import java.util.Random;
public class Util {
/**
* 工具類無需創建對象,將構造器私有化
*/
private Util() {
}
/**
* 靜態方法
*/
public static String createVerifyCode(int n){
//開發驗證碼
//1.定義變量,保存驗證碼
String code = "";
//2.定義變量,記住全部驗證碼字符
String data = "qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNMM1234567890";
//3. 定義循環生成隨機
Random r= new Random();
for (int i = 0; i < n; i++) {
//獲取隨機索引對應字符,連接給code
int index= r.nextInt(data.length());
code += data.charAt(index);
}
return code;
}
} return code;
}
}
練習
package d2_static_util;
public class Test2 {
public static void main(String[] args) {
int[] arr = {};
int[] arr1 = null;
int[] arr2 = {12, 23, 34};
System.out.println(ArrayUity.toString(arr));
System.out.println(ArrayUity.toString(arr1));
System.out.println(ArrayUity.toString(arr2));
}
}
package d2_static_util;
public class ArrayUity {
/**
* 私有構造器
*/
private ArrayUity() {
}
/**
* 工具方法靜態方法
*/
public static String toString(int[] arr){
//1.校驗
if(arr == null){
return null;
}
//2.拼接內容,返回
//result存儲
String result = "[";
for (int i = 0; i < arr.length; i++) {
result += (i == arr.length -1 ?arr[i] : arr[i] + ",");
}
result += "]";
return result;
}
}
代碼塊
-
類的五大成分(成員變量,構造器,方法,代碼塊,內部類),定義在類中方法外
-
java類下,使用{}括起來的就是代碼塊
- 靜態代碼塊:通過static關鍵字修飾,隨著類的加載而加載,自動觸發,只執行一次
public class StaticDemo1 {
public static String schoolName;
/**
* 靜態代碼塊,有static修飾,屬于類,與類一起優先加載,自動觸發執行
* 可以用于初始化,靜態資源
*/
static {
System.out.println("------------------------");
schoolName = "66學校";
}
public static void main(String[] args) {
//靜態代碼塊
System.out.println(schoolName);
}
}
- 構造代碼塊:每次創建對象的時候,調用構造器執行,都會執行該代碼塊中的代碼,并且在構造器執行前執行
package d3_static_code;
public class StaticDemo2 {
public String name;
public StaticDemo2(){
System.out.println("無參構造器被觸發執行了");
}
/*
構造代碼塊,實例代碼塊,屬于對象,調用構造器時先執行,沒有static修飾
初始化實例資源
*/
{
name = "張三"
System.out.println("=========實例代碼塊========");
}
public static void main(String[] args) {
StaticDemo2 s1 = new StaticDemo2();
StaticDemo2 s2 = new StaticDemo2();
}
}
- 靜態代碼塊應用案例
package d3_static_code;
import d2_static_util.ArrayUity;
import java.util.ArrayList;
public class StaticDemo3 {
/**
* 定義靜態集合,這樣靜態集合只加載一個,只需要一幅牌
* static修飾,表示只在內存中存儲一份,可以被共享,修改
*/
public static ArrayList<String> cards = new ArrayList<>();
/*
在程序main方法運行前,把54牌放進去,后續直接使用
*/
static {
//靜態代碼塊,隨著類的加載而加載,自動觸發,執行一次
//定義數組存儲點數
String[] sizes = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
//定義數組存儲花色
String[] colors = {"?","?","?","?"};
//先遍歷點數
for (int i = 0; i < sizes.length; i++) {
//sizes[i]
//遍歷花色
for (int j = 0; j < colors.length; j++) {
//colors[j]
String card = colors[j] + sizes[i];
cards.add(card);
}
}
//大小王
cards.add("小");
cards.add("大");
}
public static void main(String[] args) {
System.out.println("新牌" + cards);
}
}
單例設計模式
-
設計模式,問題的最優解法,有20多種
-
單例模式,保證系統中,應用該模式的類永遠只有一個實例,一個類只能創建一個對象
餓漢單例設計模式
-
用類獲取對象的時候,對象已經提前創建好了
-
定義一個類,構造器私有
-
定義靜態變量,存儲一個對象
-
public class SingleInstance {
//2.餓漢單例在獲取對象前,對象已經提前準備好
//對象只能是一個,所以定義靜態成員變量
public static SingleInstance instance = new SingleInstance();
//1. 私有構造器
private SingleInstance() {
}
}
public class Test {
public static void main(String[] args) {
SingleInstance s1 = SingleInstance.instance;
SingleInstance s2 = SingleInstance.instance;
System.out.println(s1 == s2);
}
}
懶漢單例設計模式
-
真正需要對象時,才去創建一個對象(延遲加載對象)
-
構造器私有(單例)
-
靜態變量存儲對象
-
提供方法返回單例對象
-
package d4_sttatic_danli;
//懶漢單例的思想
public class SinglrInstance2 {
//2。定義靜態成員變量存儲單例對象,只加載一次
//私有化
private static SinglrInstance2 instance2;
//3.提供方法返回單例對象
public static SinglrInstance2 getInstance(){
if(instance2 == null){
//第一次,需要創建對象
instance2 =new SinglrInstance2();
}
return instance2;
}
//1. 構造器私有
private SinglrInstance2(){
}
}
package d4_sttatic_danli;
public class Test2 {
public static void main(String[] args) {
SinglrInstance2 sq = SinglrInstance2.getInstance();
SinglrInstance2 sq1 = SinglrInstance2.getInstance();
System.out.println(sq == sq1);
}
}
繼承
-
提高代碼復用性
-
java中關鍵字extends,使用這個關鍵字,可以讓一個類和另一個類建立起父子關系
-
字類繼承父類后,可以直接使用父類的屬性和方法,字類更強大
package d5_extends;
//作為父類
public class People {
public void run(){
System.out.println("人會跑");
}
}
package d5_extends;
// 學生類,字類
public class Student extends People {
}
package d5_extends;
public class Test {
public static void main(String[] args) {
//繼承
Student s = new Student();
s.run();
}
}
繼承設計規范
-
字類們相同特征(共性屬性,共性方法)放在父類中定義,
-
字類獨有的屬性,方法,行為應該定義在字類自己里面
package d6;
public class People { //父類
private String name;
private int age;
//方法,查看課表
public void qc(){
System.out.println(name + "在查看課表");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package d6;
public class Student extends People { //繼承
//字類獨有行為
public void wi(){
System.out.println(getName() + "寫作業了");
}
}
package d6;
public class Test {
public static void main(String[] args) {
//基礎的設計思想
Student s = new Student();
s.setName("張三");//使用父類
s.setAge(23);//使用父類
System.out.println(s.getAge());//使用父類
System.out.println(s.getName());//使用父類
s.qc();//使用父類
s.wi();//使用字類
}
}
內存運行原理
繼承的特定
-
字類可以繼承父類的屬性和行為,但是不能繼承父類的構造器
-
java是單繼承模式,一個類只能繼承一個直接父類
-
java不支持多繼承,但支持多層繼承
-
Java中所有類都是Object類的字類
繼承09,14
繼承后成員變量,成員方法的訪問特點
-
就近原則
-
局部沒有找字類,字類沒有找父類,父類沒有報錯
-
字類和父類出現重名成員,要使用父類的成員加super關鍵字
package d8;
public class Test {
public static void main(String[] args) {
//繼承后,成員的訪問特定
//就近原則
Dog d = new Dog();
d.lookDoor();//調用字類
d.run();//調用子類的
d.showName();
}
}
class Animal {
public String name = "動物名";
public void run(){
System.out.println("動物可以跑");
}
}
class Dog extends Animal{
public String name = "狗名";
public void lookDoor(){
System.out.println("狗看門");
}
public void run(){
System.out.println("狗跑的很快");
}
public void showName(){
String name = "局部名";
System.out.println(name);
System.out.println(this.name);//當前對象name,this代表當前對象的地址
System.out.println(super.name);//字類和父類重名時,要使用父類的成員,加關鍵字super
}
}
繼承后方法重寫
-
在繼承關系中,字類和父類出現了一模一樣的方法聲明,我們就稱字類這個方法是重寫的方法
-
當字類需要父類的功能,但是父類的功能不能滿足自己的需求時,字類就可以重寫父類中的方法
-
方法重寫的注意事項和要求,
one extend重寫校驗注解,加上之后,方法必須是正確重寫,提高程序的可讀性-
重新方法的名稱,形參列表必須和被重寫方法的名稱和參數保持一致
-
私有方法不能被重寫
-
字類重寫父類方法時,訪問權限大于或等于父類
-
字類不能重寫父類的靜態方法,重寫會報錯
-
package dd9;
public class Test {
public static void main(String[] args) {
NewPhone p = new NewPhone();
p.call();
p.semndMag();
}
}
//父類
class Phone{
public void call(){
System.out.println("打電話");
}
public void semndMag(){
System.out.println("發短信");
}
}
//字類
class NewPhone extends Phone{
@Override //重寫校驗注解,加上之后,方法必須是正確重寫,提高程序的可讀性
public void call(){
super.call();
System.out.println("視頻通話");
}
@Override
public void semndMag(){
super.semndMag();
System.out.println("發送圖片");
}
}
繼承后字類構造器的特點
-
字類中所有的構造器都會默認訪問父類中的無參構造器,再執行自己
-
字類再初始化的時候,有可能會使用到父類中的數據,如果父類沒有初始化,字類講無法使用父類的數據
-
字類初始化前,一定要調用父類構造器完成父類數據空間的初始化
package d10;
public class Test {
public static void main(String[] args) {
//繼承后字類構造器特定
Dog d = new Dog();
System.out.println(d);
Dog d2 = new Dog("hhh");
System.out.println(d2);
}
}
package d10;
public class Animal {
public Animal(){
System.out.println("父類無參構造器執行");
}
}
package d10;
import jdk.swing.interop.SwingInterOpUtils;
public class Dog extends Animal{
public Dog(){
System.out.println("字類無參構造器");
}
public Dog(String name){
System.out.println("字類有參構造器");
}
}
繼承后,字類構造器訪問父類的有參構造器
- super調用有參數構造器的作用,初始化繼承自父類的數據
package d11;
public class Test {
public static void main(String[] args) {
//字類構造器訪問父類有參構造器
Teacher t = new Teacher("dilei", 55);
System.out.println(t.getAge());
System.out.println(t.getName());
}
}
package d11;
public class People {
private String name;
private int age;
public People(String name, int age) {
this.name = name;
this.age = age;
}
public People() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package d11;
public class Teacher extends People{
public Teacher (String name, int age){
//調用父類有參構造器,初始化繼承自父類的數據
super(name, age);
}
}
this和super
-
this代表本類對象的引用
-
super,代表父類存儲空間
-
this和super都要在構造器的第一行,兒二者不能在同一個構造器中
package d12;
public class Test {
public static void main(String[] args) {
//理解this
Student s1 = new Student("好家伙", "666");
System.out.println(s1.getName());
System.out.println(s1.getSchoolName());
Student s2 = new Student("shabi");
System.out.println(s2.getName());
System.out.println(s2.getSchoolName());
}
}
package d12;
public class Student {
private String name;
private String schoolName;
public Student() {
}
public Student(String name){
//借用本類兄弟構造器
this(name, "黑馬");
}
public Student(String name, String schoolName) {
this.name = name;
this.schoolName = schoolName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
}
day02
包
-
用來管理不同的類,類似于文件夾
-
導包:相同包下的類可以直接使用,不同包下的類必須導包才能使用
package d1_package;
//導包
import d1_package.d1_package2.Student;
public class Test {
public static void main(String[] args) {
//1.同一個包下的可以直接訪問
System.out.println(User.onlineNumber);
//2.不同包下的類,必須先導包才可以訪問
Student s =new Student();
//3.如果這個類中使用不同包下的相同類名,默認只能導入一個類的包,另一個類的包,要使用全名訪問
d1_package.d1_packer3.Student s2 = new d1_package.d1_packer3.Student();
}
}
權限修飾符
-
控制修飾的成員能夠被訪問的范圍
-
可以修飾成員變量,方法,構造器,內部類,不同權限修飾符修飾的成員能夠被訪問的范圍將受限制
-
有四種作用由小到大
- private,只能在當前類中訪問
- 缺省,能在同一個類,同一個包中的其他類訪問
- protected,同一個類中,同一個包中的其他類,不同包下的字類(使用字類創建新對象)
- public,同一個類中,同一個包中的其他類,不同包下的字類,不同包下的無關類
-
自定義成員滿足以下要求:
- 成員變量一般私有
- 方法一般公開
- 如果該成員只希望本類訪問,使用private
- 如果該成員只希望本類,同一個包下的其他類和字類訪問,使用protected
final關鍵字
- 最終的意思,可以修飾類,方法,變量
- 修飾類:表明該類試最終類,不能被繼承
- 修飾方法:表示該方法試最終方法,不能被重寫
- 修飾變量:表明該變量最后一次賦值,不能被再次賦值(有且只能賦值一次)
public class Test {
public static void main(String[] args) {
//final語法
//final修飾類,類不能被繼承,工具類可能使用
//final修飾方法,不能被重寫
//final修飾變量,變量有且僅能被賦值一次
}
}
/*class Student extends People{
@Override
public void eat(){
System.out.println("學生也要吃");
}
}*/
class People{
public final void eat(){
System.out.println("人要吃飯");
}
}
/*
class wolf extends Animal
final class Animal{}*/
public class Test2 {
//final修飾的靜態成員變量,常量
public static final String schoolName = "heima";
//實例成員變量,幾乎不用
private final String name = "3333";
public static void main(String[] args) {
//final修飾變量的作用
//局部變量和成員變量,
//局部變量
final double score = 3.14;
// score = 3.3;第二次賦值
// schoolName = "dddd"第二次賦值
nam
}
}
-
注意:
-
final修飾的變量是基本類型,那么變量存儲的數據值不能發生改變
-
final修飾的變量是引用類型,那么變量可存儲的地址值不能發生改變,但是地址指向的對象內容是可以發生變化的
-
public class Test1 {
public static void main(String[] args) {
//final修飾引用類型的變量,地址值不能發生改變,但是指向的內容可以改變
final Teachers t = new Teachers("學習");
System.out.println(t.getHobby());
t.setHobby("66666666666");
System.out.println(t.getHobby());
}
}
class Teachers{
private String hobby;
public Teachers(String hobby) {
this.hobby = hobby;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
常量
- 就是使用了public static final修飾的成員變量,必須有初始化值,指向過程中值不能被改變
- 作用和好處:可以用作系統的配置信息,方便維護,提高可讀性
- 命名規范:英文單詞全部大寫,多個單詞下劃線連接起來
public class d1 {
public static final String SCHOOL_NAME = "44444";
public static void main(String[] args) {
// 常量的使用
System.out.println(SCHOOL_NAME);
}
}
-
常量的執行原理
- 在編譯階段會執行"宏替換",把使用常量的地方全部替換成真實的字面量
常量做信息標志和分類
- 代碼可讀性好,實現軟編碼形式
枚舉類
-
java中特殊類型
-
做信息的標志和信息的分類
public enum Season {
//枚舉第一行,羅列枚舉類的對象名稱,建議全隊大寫
SPRING, SUMMER, AUTUMN, WINTER;
}
javac進行編譯
javap進行反編譯
Compiled from "Season.java"
public final class Season extends java.lang.Enum<Season> {
public static final Season SPRING;
public static final Season SUMMER;
public static final Season AUTUMN;
public static final Season WINTER;
public static Season[] values();
public static Season valueOf(java.lang.String);
static {};
}
- 枚舉的特點
- 枚舉都是繼承了枚舉類型,java.lang.Enum
- 枚舉都是最終類,不可以被繼承
- 枚舉類的構造器是私有的,枚舉對外不能創建對象
- 枚舉類的第一行默認都是羅列枚舉對象的名稱
- 枚舉類,相當于多例模式
抽象類
- 在java中abstract是抽象的意思,可以修飾類,成員方法
//抽象類和抽象方法,都有sbstract修飾
public abstract class Animal {
//抽象方法不能寫,方法體代碼
public abstract void run();
}
//抽象方法只有方法簽名,不能申明方法體
//一個類中如果定義了抽象方法,必須聲明這個類成抽象類。
-
使用場景:一般作為父類,讓字類繼承
-
當父類知道字類要完成某些行為,但是每個字類該行為的實現方法不同,父類就把該行為定義成抽象方法的形式,具體實現交給字類去完成,此時這個類就可以聲明成抽象類
抽象類的案例
public abstract class Card {
private String name;
private double money;
//定義支付方法,抽象方法
public abstract void pay(double money);
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
public class GoldCard extends Card{
@Override
public void pay(double money2) {
System.out.println("當前消費" + money2);
System.out.println("當前余額" + getMoney());
double rs = money2 * 0.8;
System.out.println(getName() + "實際支付" + rs);
//跟新余額
setMoney(getMoney() - rs);
}
}
public class Test {
public static void main(String[] args) {
//抽象類的基本使用,做父類被繼承,在重寫抽象方法
GoldCard g = new GoldCard();
g.setMoney(10000);
g.setName("dilei");
g.pay(300);
System.out.println("剩余" + g.getMoney());
}
}
抽象類的特征,注意事項
-
類有的成分,抽象類都有
-
抽象類中不一定又抽象方法,有抽象方法一定是抽象類
-
類繼承了抽象類,必須重寫完抽象類的全部抽象方法,否則這個類定義成抽象類
-
不能用abstract修飾變量,代碼塊,構造器
-
抽象類不能創建對象
-
abstract和final互斥
模板方法模式
-
把功能定義成一個模板方法,放在抽象類中,模板方法中只定義通用且能確定的代碼
-
模板方法把不能確實的功能,定義成抽象方法讓字類實現
-
模板方法用final修飾,不能讓字類重寫
接口
-
interface關鍵字,接口也是一種規范
-
jdk8之前的接口只能寫常量和抽象方法
//聲明了接口
public interface InterfaceDemo {
//成分特點,jdk8之前接口中只能有抽象方法和常量
//常量
//由于接口體現規范思想,規范默認公開,代碼層面,public abstract final可以省略
String SCHOOL_NAME1 = "黑馬";
public static final String SCHOOL_NAME = "黑馬";
//抽象方法
//由于接口體現規范思想,規范默認公開,代碼層面,public abstract可以省略
void ruu();
public abstract void run();
}
接口的基本使用
-
接口是用來被類實現(implements)的,實際接口的類稱為實現類,實現類可以理解成所謂的字類
-
implements,接口可以被類多實現,必須重寫完接口的全部抽象方法
public interface SpotrMan {
void run();//接口
void bisai();
});
}
public interface law {
void rule();
}
public class pingpang implements SpotrMan, law {
private String name;
public pingpang(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name + "跑步");
}
@Override
public void bisai() {
System.out.println(name + "參加比賽");
}
@Override
public void rule() {
System.out.println(name + "守法");
}
}
public class Test {
public static void main(String[] args) {
//接口的基本使用,被類實現
pingpang p = new pingpang("張繼科");
p.run();
p.bisai(); q
p.rule();
}
}
接口和接口的關系:多繼承
- 一個接口可以繼承多個接口
- 接口繼承的作用:整合多個接口為同一個接口,便于字類實現
public interface laww {
void rulee();
}
public interface People {
void eat();
void sleep();
}
public interface SportM extends laww,People {
void run();
void bisai();
}
public class BasketBallMan implements SportM{
@Override
public void eat() {
}
@Override
public void sleep() {
}
@Override
public void run() {
}
@Override
public void bisai() {
}
@Override
public void rulee() {
}
}
public class Test {
public static void main(String[] args) {
//理解接口多繼承
}
}
jdk8開始新增方法
package d13_interface_jdk8;
public interface SportMa {
/**
* jdk8新增默認方法,(實例方法)
* 必須default修飾,默認是public修飾
* 默認方法吊用,接口不能創建對象,過繼給實現類,實現類的對象吊用
*/
default void run(){
System.out.println("paodekaui");
go();
};
/**
*靜態方法
* 使用static修飾,默認public修飾
* 接口的靜態方法,接口名自己吊用
*/
public static void inAdd(){
System.out.println("學習java新增方法");
}
/**
* jdk9新增方法,私有方法(實例方法)
* 必須在接口內部訪問
*/
private void go(){
System.out.println("開始跑");
}
}
class PingPan implements SportMa{
}
class Test{
public static void main(String[] args) {
PingPan p = new PingPan();
p.run();
SportMa.inAdd();
}
}
接口注意事項
-
接口不能創建對象
-
一個類可以實現多個接口,多個接口中有同樣的靜態方法不沖突(只能接口自己調用 接口.方法名)
-
一個類繼承父類,同時實現接口,父類中和接口中有同名的方法,默認使用父類的
-
一個類實現多個接口,多個接口中存在同名的默認方法,不沖突,這個類重寫該方法即可
-
一個接口繼承多個接口,如果多個接口中規范沖突則不能繼承
day 03
多態
-
同類型的對象,執行同一個行為,會表現出不同的行為特征
-
多態的前提:有繼承/實現關系;有父類引用指向字類對象;有方法重寫
-
**多態的常見形式
父類類型 對象名稱 = new 字類構造器
接口 對象名稱 = new 實現類構造器
public class Test {
public static void main(String[] args) {
//1.多態的形式 父類類型 對象名稱 = new 字類構造器
Animal a = new Dog();
a.run();//編譯看左邊,運行看右邊
System.out.println(a.name);//編譯看左,運行也看左(多態看重行為)
Animal a2 = new Tortoise();
a2.run();
System.out.println(a2.name);
}
}
多態中成員訪問特點
-
方法調用:編譯看左邊,運行看右邊
-
變量調用:編譯看左邊,運行也看左邊
多態的優勢
-
在多態形式下,右邊對象可以實現解耦合,便于擴展個和維護
-
定義方法的時候:使用父類作為參數,該方法就可接收一切字類對象,體現出多態的擴展性和便利
問題
- 多態下不能使用字類的獨有功能(編譯看左邊)
多態下引用數據類型的類中轉換
-
強制類型轉換:子類 對象變量 = (字類)父類類型的變量
-
作用:可以解決多態的劣勢,可以實現調用字類獨有的功能
-
強轉轉換之前,使用instanceof判斷當前對象的真實類型,再進行強制轉換
變量名 instanceof 真實類型
判斷關鍵字左邊的變量指向對象的真實類型,是否是右邊的類型或者是其字類類型,是則返回true,反之false
public class Test {
public static void main(String[] args) {
//自動類型轉換
Animal a = new Dog();
a.run();
//強制類型轉換
Animal a2 = new Tortoise();
a2.run();
if(a2 instanceof Tortoise){
Tortoise t = (Tortoise) a2;
t.lay();
}else if(a2 instanceof Dog){
Dog d = new Dog();
d.look();
}
}
}
案例
package d4;
public class Computer {
private String name;
public Computer(String name) {
this.name = name;
}
public void start(){
System.out.println(name + "開機了");
}
//提供安裝usb設備的入口
public void installUsb(Usb usb){
//多態,父類接口作為參數,所有行為對象都能進來\
usb.connect();
//獨有功能,先判斷再強轉
if(usb instanceof KeyBoard){
KeyBoard k = (KeyBoard) usb;
k.keyDown();
}else if(usb instanceof Mouse){
Mouse m = (Mouse) usb;
m.dbClick();
}
usb.unconnect();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package d4;
public class KeyBoard implements Usb{//實現類
private String name;
public KeyBoard(String name) {
this.name = name;
}
@Override
public void connect() {
System.out.println("連接電腦");
}
//獨有功能
public void keyDown(){
System.out.println("鍵盤敲擊");
}
@Override
public void unconnect() {
System.out.println("拔出");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package d4;
public class Mouse implements Usb{
private String name;
public Mouse(String name) {
this.name = name;
}
@Override
public void connect() {
System.out.println("連接電腦");
}
//獨有功能
public void dbClick(){
System.out.println("點擊鼠標");
}
@Override
public void unconnect() {
System.out.println("拔出");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package d4;
public class Test {
public static void main(String[] args) {
//創建電腦對象
Computer c= new Computer("外星人");
c.start();
//創建鼠標,鍵盤對象
Usb k = new KeyBoard("雙飛燕");
c.installUsb(k);
Usb m = new Mouse("邏輯");
c.installUsb(m);
}
}
package d4;
/**
* usb接口==規范
*/
public interface Usb {
//接入和拔出
void connect();
void unconnect();
}
內部類
-
定義在一個類里面的類,里面的類可以理解成寄生,外部類可以理解成宿主
-
使用場景:事物的內部,還有一部分需要一個完整的結構進行描述,而這個內部的完整結構又只為外部事物提供服務,那么內部的完整結構可以選擇內部類來設計
-
內部類通??梢苑奖阍L問外部類的成員,包括私有成員
-
內部類提供更好的封裝性,內部類本身就可以用prviate protectecd等修飾,封裝性可以做更多控制
靜態內部類
-
有static修飾,屬于外部類本身
-
特點和使用與普通類一樣,類有的成分都有,只是位置在別人里面
-
可以直接訪問外部類的靜態成員,不能直接訪問外部類的實例成員
-
實際使用較少
package d5;
//外部類
public class Outer {
public static int a =10;
//靜態成員內部類
public static class Inner{
private String name;
private int age;
public static String school_name;
public void show(){
System.out.println(name);
System.out.println(a);
}
public Inner(String name, int age) {
this.name = name;
this.age = age;
}
public Inner() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static String getSchool_name() {
return school_name;
}
public static void setSchool_name(String school_name) {
Inner.school_name = school_name;
}
}
}
public class Test {
public static void main(String[] args) {
//外部類名.內部類 對象名 = new 外部類名.內部類
Outer.Inner i = new Outer.Inner();
i.setName("sha");
i.show();
}
}
成員內部類
-
無static修飾,屬于外部類對象
-
jdk16之前,成員內部類中不能定義靜態成員,jdk16開始可以定義靜態成員
package d6;
//外部類
public class Outer {
//成員內部類
public class Iner {
private int age;
private String name;
public static int a = 100;//jdk16開始支持靜態成員
public void show(){
System.out.println(name);
}
public static void test(){
System.out.println(a);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static int getA() {
return a;
}
public static void setA(int a) {
Iner.a = a;
}
}
}
package d6;
public class Test {
public static void main(String[] args) {
//外部類名.內部類名 對象名 = new 外部類構造器.new 內部類構造器
Outer.Iner in = new Outer().new Iner();
in.setName("sha");
Outer.Iner.test();//靜態屬于類
in.show();//實例屬于對象
}
}
- 成員內部類中,訪問外部類對象
package d6;
public class Test2 {
public static void main(String[] args) {
People.he heart = new People().new he();
heart.show();
}
}
class People{
private int heartbeat = 150;
public class he{
private int heartbeat = 110;
public void show(){
int heartbeat = 78;
System.out.println(heartbeat);//78
System.out.println(this.heartbeat);//110,實例成員變量屬于對象,用this調用當前對象
System.out.println(People.this.heartbeat);//150,
}
}
}
局部內部類 -沒啥大用
匿名內部類
-
沒有名字的局部內部類,定義在方法,代碼塊中等
-
方便創建字類對象,簡化編寫
-
匿名內部類是一個沒有名字的內部類
-
匿名內部類寫出來就會產生一個匿名內部類的對象
package d7;
public class Test {
public static void main(String[] args) {
Animal a = new Animal(){
@Override
public void run() {
System.out.println("老虎跑的快");
}
};
a.run();
}
}
/*class Tiger extends Animal{
@Override
public void run() {
System.out.println("老虎跑的快");
}
}*/
abstract class Animal{
public abstract void run();
}
匿名內部類使用形式
- 可以作為方法的參數傳輸
package d8;
import org.w3c.dom.ls.LSOutput;
public class Test {
public static void main(String[] args) {
//匿名內部類使用形式
go(new Swimming() {//重寫接口的方法,匿名內部類的對象
@Override
public void swim() {
System.out.println("學生游泳");
}
});
System.out.println("-----------------");
Swimming s2 = new Swimming() {//重寫接口的方法,匿名內部類的對象
@Override
public void swim() {
System.out.println("老師游泳");
}
};
go(s2);
}
//學生,老師,運動員,參加游泳比賽
public static void go(Swimming s){
System.out.println("游");
s.swim();
}
}
/*class Student implements Swimming{
@Override
public void swim() {
System.out.println("學生游泳");
}
}*/
interface Swimming{
void swim();
}
常用API
- 應用程序編程接口,java寫好的方法,直接使用
Object-toString
-
一個類中默認繼承了Object類,要么簡潔繼承Object類,是java中的祖宗類
-
Object類的方法是一切字類都可以直接使用的
-
public String toString()--默認返回當對象在堆內存中的地址信息,類的全限名@內存地址,
-
讓字類重寫,以便返回字類對象的內容
package d9;
public class Student {
private String name;
private char sex;
private int age;
public Student() {
}
public Student(String name, char sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex=" + sex +
", age=" + age +
'}';
}
}
package d9;
//Object類
public class Test {
public static void main(String[] args) {
Student s = new Student("zhang", '男' , 19);
// String rs = s.toString();
// System.out.println(rs);
//直接輸出對象變量,toString默認可以省略不寫
System.out.println(s.toString());
System.out.println(s);
}
}
Object-equals
package d9;
import java.util.Objects;
public class Student {
private String name;
private char sex;
private int age;
public Student() {
}
public Student(String name, char sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//重寫toString,返回對象內容
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex=" + sex +
", age=" + age +
'}';
}
//重寫equals,自己動議規則
// @Override
// public boolean equals(Object o){
// Student s2 = (Student) o;//o是Object,里面沒有name,強制轉換成Student類
// //判斷o是不是學生類型
// if(o instanceof Student){
// //判斷兩個對象內容
//// if(this.name.equals(s2.name) && this.age == s2.age
//// && this.sex == s2.sex){
//// return true;
//// }else {
//// return false;
//// }
// return this.name.equals(s2.name) && this.age == s2.age
// && this.sex == s2.sex;
//
// }else {
// return false;
// }
// }
@Override
public boolean equals(Object o) {
if (this == o) return true;//判斷是否是同一對象
if (o == null || getClass() != o.getClass()) return false;//null返回false,getClass()獲取的類型不是o的類型,返回false
Student student = (Student) o; //類中轉換
return sex == student.sex && age == student.age && Objects.equals(name, student.name);
}
}
package d9;
//equals
public class Test2 {
public static void main(String[] args) {
Student s1 = new Student("zhang",'男',90);
Student s2 = new Student("zhang",'男',90);
//默認比較兩個對象地址,==也可以
System.out.println(s1.equals(s2));
System.out.println(s1 == s2);
}
}
Objects-equals
-
Objects類和Object還是繼承關系,Objects類是從jdk1,7開始才有的
-
Objects的eauals方法比較結果一樣,更安全
package d10;
import java.util.Objects;
//Objects -equals
public class Test {
public static void main(String[] args) {
String s1 = null;
String s2 = "s";
//System.out.println(s1.equals(s2));//可能出現空值異常
System.out.println(Objects.equals(s1, s2));
}
}
Objects-isnull
- 判斷是否為null
System.out.println(Objects.isNull(s1));
StringBuilder
- StringBuilder,是一個可變的字符串類,可以看作一個對象容器
- 作用:提高字符串的操作效率,如拼接,修改
package d11;
//StringBuilder,使用,原理
public class Test {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append(22);
sb.append(false);
System.out.println(sb);
StringBuilder sb1 = new StringBuilder();
//鏈式編程
sb1.append("a").append("c").append("c");
System.out.println(sb1);
//反轉
sb1.reverse().append(110);
System.out.println(sb1);
System.out.println(sb1.length());
//StringBUilde,只是拼接字符串的手段,效率好
//最終的目的要恢復成String
//恢復成String
String sr = sb1.toString();
System.out.println(sr);
}
}
案例
package d11;
public class Test2 {
public static void main(String[] args) {
int[] arr1 = null;
System.out.println(toS(arr1));
int[] arr2 = {11,22,33};
System.out.println(toS(arr2));
}
//1,定義方法接收整型數組
public static String toS(int[] arr){
//拼接內容
if(arr != null){
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < arr.length; i++) {
sb.append(arr[i]).append(i == arr.length - 1 ? "" : ", ");
}
sb.append("]");
return sb.toString();
}else {
return null;
}
}
}
Math-工具類
-
包含執行基本數字運算的方法,Math類沒有提供公開的構造器
-
都是靜態類,通過類名直接調用
package d12;
public class test {
public static void main(String[] args) {
//1.取絕對值,返回正數
System.out.println(Math.abs(10));//10
System.out.println(Math.abs(-10.8));//10.8
//2.向上取整
System.out.println(Math.ceil(4.00000000000002));//5
//3.向下取整
System.out.println(Math.floor(4.999999999991));//4
//4.求指數次方
System.out.println(Math.pow(2, 3));//2^3=8
//5.四舍五入
System.out.println(Math.round(4.49));
System.out.println(Math.round(4.51));
//6.取隨機數
System.out.println(Math.random());//0.0-1.0(包前不包后)
//3-9直接的隨機數(減加法)
//0-1 * 6 + 3
int d = (int)(Math.random() * 7) + 3;
System.out.println(d);
}
}
system
- 功能是通用的,不能創建對象,靜態方法
package d13;
import java.util.ArrayList;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
System.out.println("開始");
//1. System.exit(0);//jvm,0,正常終止
//計算機時間起源,返回1970-1-1 00.00.00
//2.算是c語言的生日
// long time = System.currentTimeMillis();
// System.out.println(time);
// //進行時間的計算
// long startTime = System.currentTimeMillis();
// for (int i = 0; i < 100000; i++) {
// System.out.println("輸出" + i);
// }
// long endTime = System.currentTimeMillis();
// System.out.println((endTime - startTime)/1000.0 + "s");
/*arraycopy(Object src參數1, int srcPos拷貝開始位置,
Object dest復制到, int destPos粘貼位置,
int length拷貝個數);*/
//數組拷貝
int[] arr = {1,2,3,4,5,6,7,8};
int[] arr2 = new int[6];
System.arraycopy(arr, 3, arr2, 2, 3);
System.out.println(Arrays.toString(arr2));
System.out.println("結束");
}
}
BigDecimal
- 解決浮點型運算精度失真的問題
package d14;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Test {
public static void main(String[] args) {
double a = 0.1;
double b = 0.2;
double c = a + b;
System.out.println(c);
//包裝浮點型數據成為大數據對象 BigDeciaml
BigDecimal a1 = BigDecimal.valueOf(a);
BigDecimal b1 = BigDecimal.valueOf(b);
// BigDecimal c1 = a1.add(b1);
// BigDecimal c1 = a1.subtract(b1);
// BigDecimal c1 = a1.multiply(b1);
BigDecimal c1 = a1.divide(b1);
System.out.println(c1);
double rs = c1.doubleValue();
System.out.println(rs);
//注意:BigDecimal,一定要精度運算
BigDecimal a11 = BigDecimal.valueOf(10.0);
BigDecimal b11 = BigDecimal.valueOf(3.0);
/*
* 參數1是除數
* 參數2保留小數位
* 參數3舍人
* */
BigDecimal c11 = a11.divide(b11, 2, RoundingMode.HALF_UP);
System.out.println(c11);
}
}

浙公網安備 33010602011771號