Java基础编程(高级部分)

1. 类变量和类方法

1.1 什么是类变量

        类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值同样任何一个该类的对象去修改它时,修改的也是同一个变量。

1.2 定义类变量

1.3 访问类变量

 类名.类变量名
或者 对象名.类变量名【静态变量的访问修饰符的访问权限和范围和普通属性是一样的。】
推荐使用: 类名.类变量名;
代码:

package com.zakedu.static_;public class VisitStatic{public static void main(String[]args){//类名.类变量名
//说明:类变量是随着类的加载而创建,所以即使没有创建对象实例也可以访问
System.out.println(A.name);A a = new A();//通过对象名.类变量名
System.out.println("a.name="+a.name);} }class A{//类变量
//类变量的访问,必须遵守相关的访问权限.public static String name ="知昂可";//普通属性/普通成员变量/非静态属性/非静态成员变量/实例变量
private int num = 10;
}

1.4 类变量使用注意事项

1. 什么时候需要用类变量
当我们需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量):
比如:定义学生类,统计所有学生共交多少钱。Student (name, staticfee)
2. 类变量与实例变量(普通属性)区别
类变量是该类的所有对象共享的,而实例变量是每个对象独享的。
3. 加上static称为类变量或静态变量,否则称为实例变量/普通变量/非静态变量
4. 类变量可以通过类名.类变量名或者对象名.类变量名来访问,但java设计者推荐我们使用类名.类变量名方式访问。【前提是满足访问修饰符的访问权限和范围】
5. 实例变量不能通过类名.类变量名方式访问。
6. 类变量是在类加载时就初始化了,也就是说,即使你没有创建对象,只要类加载了,就可以使用类变量了。
7. 类变量的生命周期是随类的加载开始,随着类消亡而销毁。
代码:

package com.zakedu.static_;
public class StaticDetail{public static void main(String[]args){B b = new B();//System.out.println(B.n1);System.out.println(B.n2);//静态变量是类加载的时候,就创建了,所以我们没有创建对象实例
//也可以通过类名.类变量名来访问
System.out.println(C.address);}}class B {public int n1 = 100;public static int n2 = 200;}class C {public static String address = "北京";}

1.5 类方法基本介绍

1.6 类方法的调用

1.7 类方法应用案例

 package com.zakedu.static_;public class StaticMethod {
public static void main(String[] args) {//创建2个学生对象,叫学费
Stu tom = new Stu("tom");//tom.payFee(100);Stu.payFee(100);//对不对?对
Stu mary = new Stu("mary");//mary.payFee(200);Stu.payFee(200);//对
//输出当前收到的总学费
Stu.showFee();//300//如果我们希望不创建实例,也可以调用某个方法(即当做工具来使用)//这时,把方法做成静态方法时非常合适
System.out.println("9 开平方的结果是=" + Math.sqrt(9));System.out.println(MyTools.calSum(10, 30));} }//开发自己的工具类时,可以将方法做成静态的,方便调用
class MyTools {//求出两个数的和
public static double calSum(double n1, double n2) {
return n1 + n2;}//可以写出很多这样的工具方法...}class Stu {private String name;//普通成员
//定义一个静态变量,来累积学生的学费
private static double fee = 0;public Stu(String name) {this.name = name;}//说明
//1. 当方法使用了static修饰后,该方法就是静态方法
//2. 静态方法就可以访问静态属性/变量
public static void payFee(double fee) {Stu.fee += fee;//累积到
}public static void showFee() {System.out.println("总学费有:" + Stu.fee);}}

1.8 类方法经典的使用场景

1.9 类方法使用注意事项

1) 类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区:
        类方法中无this的参数
        普通方法中隐含着this的参数
2) 类方法可以通过类名调用,也可以通过对象名调用。
3) 普通方法和对象有关,需要通过对象名调用,比如对象名.方法名(参数),不能通过类名调用。
4) 类方法中不允许使用和对象有关的关键字,比如this和super。普通方法(成员方法)可以。
5) 类方法(静态方法)中只能访问静态变量或静态方法。
6) 普通成员方法,既可以访问非静态成员,也可以访问静态成员。
小结: 静态方法,只能访问静态的成员,非静态的方法,可以访问静态成员和非静态成员(必须遵守访问权限)
代码:

 packagecom.zakedu.static_;public class StaticMethodDetail{public static void main(String[]args){D.hi();//ok//非静态方法,不能通过类名调用
//D.say();,错误,需要先创建对象,再调用
new D().say();//可以
} }class D {private int n1 = 100;private static int n2 = 200;public void say() {//非静态方法,普通方法
}public static void hi() {//静态方法,类方法
//类方法中不允许使用和对象有关的关键字,
//比如this 和 super。普通方法(成员方法)可以。
//System.out.println(this.n1);}//类方法(静态方法)中 只能访问 静态变量 或静态方法
//口诀:静态方法只能访问静态成员.public static void hello() {System.out.println(n2);System.out.println(D.n2);//System.out.println(this.n2);不能使用
hi();//OK//say();//错误
}//普通成员方法,既可以访问 非静态成员,也可以访问静态成员
//小结: 非静态方法可以访问 静态成员和非静态成员
public void ok() {//非静态成员
System.out.println(n1);say();//静态成员
System.out.println(n2);hello();} }

1.10 练习

看看下面代码有没有错误,如果有错误,就修改,看看输出什么?

代码1:

class Person { //StaticExercise02.java 2min 时间
private int id;
private static int total =0;public static int getTotalPerson(){//id++;//错误,注销
return total;}public Person(){//构造器
total++; //total=1id=total;//id=1}}public class TestPerson{public static void main(String[]args){System.out.println("Numberoftotalis"+Person.getTotalPerson());//0Person p1 = new Person();System.out.println("Numberoftotalis"+Person.getTotalPerson());//1} }

代码2:

 class Person{//StaticExercise03.java2min看
private int id;private static int total =0;public static void setTotalPerson(inttotal){
//this.total=total;//错误,因为在static方法中,不可以使用this关键字
Person.total=total;}public Person(){//构造器
total++;id =total;}}public class TestPerson{public static void main(String[]args){Person.setTotalPerson(3);new Person();//最后total的值就是4} }//小结:记住两句话(1)静态方法,只能访问静态成员(2)非静态方法,可以访问所有的成员
//(3)在编写代码时,仍然要遵守访问权限规则

2. 理解main方法语法

2.1 深入理解main方法

提示:
1) 在main()方法中,我们可以直接调用main方法所在类的静态方法或静态属性。 14
2) 但是,不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静 态成员
代码:

package com.zakpedu.main_;public class Main01{//静态的变量/属性
private static String name="zak";//非静态的变量/属性
private int n1 = 10000;//静态方法
public static void hi(){System.out.println("Main01的hi方法");
}//非静态方法
public void cry() {System.out.println("Main01 的 cry 方法");}public static void main(String[] args) {//可以直接使用 name//1. 静态方法main 可以访问本类的静态成员
System.out.println("name=" + name);hi();//2. 静态方法main 不可以访问本类的非静态成员
//System.out.println("n1=" + n1);//错误
//cry();//3. 静态方法main 要访问本类的非静态成员,需要先创建对象 , 再调用即可
Main01 main01 = new Main01();System.out.println(main01.n1);//okmain01.cry();} }

案例演示:

3. 代码块

3.1 基本介绍

        代码化块又称为初始化块,属于类中的成员[即是类的一部分],类似于方法,将逻辑语句封装在方法体中,通过{ }包围起来。
        但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用。

3.2 基本语法

代码:

 package com.zakedu.codeblock_;public class CodeBlock01{public static void main(String[]args){Movie movie = new Movie("你好,李焕英");System.out.println("===============");Movie movie2 = new Movie("唐探3",100,"陈思诚");}}class Movie {private String name;private double price;private String director;//3 个构造器-》重载
//解读
//(1) 下面的三个构造器都有相同的语句
//(2) 这样代码看起来比较冗余
//(3) 这时我们可以把相同的语句,放入到一个代码块中,即可
//(4) 这样当我们不管调用哪个构造器,创建对象,都会先调用代码块的内容
//(5) 代码块调用的顺序优先于构造器..
{System.out.println("电影屏幕打开...");System.out.println("广告开始...");System.out.println("电影正是开始...");
}public Movie(String name) {System.out.println("Movie(String name) 被调用...");this.name = name;}public Movie(String name, double price) 
this.name = name;this.price = price;}public Movie(String name, double price, String director) {System.out.println("Movie(String name, double price, String director) 被调用...");this.name = name;this.price = price;this.director = director;} }

3.3 代码块使用注意事项

package com.zakedu.codeblock_;public class CodeBlockDetail01 {public static void main(String[] args) {//类被加载的情况举例
//1. 创建对象实例时(new)// AA aa = new AA();//2. 创建子类对象实例,父类也会被加载, 而且,父类先被加载,子类后被加载
// AA aa2 = new AA();//3. 使用类的静态成员时(静态属性,静态方法)// System.out.println(Cat.n1);//static 代码块,是在类加载时,执行的,而且只会执行一次.
// DDdd=newDD();
// DDdd1=newDD();//普通的代码块,在创建对象实例时,会被隐式的调用。
// 被创建一次,就会调用一次。
// 如果只是使用类的静态成员时,普通代码块并不会执行
System.out.println(DD.n1);//8888, 静态模块块一定会执行
}}class DD {public static int n1 = 8888;//静态属性
//静态代码块static {System.out.println("DD 的静态代码 1 被执行...");//}//普通代码块, 在new 对象时,被调用,而且是每创建一个对象,就调用一次
//可以这样简单的,理解 普通代码块是构造器的补充
{System.out.println("DD 的普通代码块...");
} }class Animal {//静态代码块static {System.out.println("Animal 的静态代码 1 被执行...");//} }class Cat extends Animal {public static int n1 = 999;//静态属性
//静态代码块static {System.out.println("Cat 的静态代码 1 被执行...");//} }class BB {//静态代码块static {System.out.println("BB 的静态代码 1 被执行...");//1} }class AAextends BB {//静态代码块static{System.out.println("AA的静态代码1被执行...");//2} }

 package com.zakedu.codeblock_;public class CodeBlockDetail02{public static void main(String[]args){A a = new A();//(1)A静态代码块01(2)getN1被调用...(3)A普通代码块01(4)getN2被调用...(5)A()构造器被调用
} }classA{{  //普通代码块System.out.println("A 普通代码块 01");}private int n2 = getN2();//普通属性的初始化static { //静态代码块System.out.println("A 静态代码块 01");}//静态属性的初始化private static int n1 = getN1();public static int getN1() {System.out.println("getN1 被调用...");return 100;}public int getN2() { //普通方法/非静态方法System.out.println("getN2 被调用...");return 200;}//无参构造器public A() {System.out.println("A() 构造器被调用");} }

package com.zakedu.codeblock_;public class CodeBlockDetail03{public static void main(String[]args){new BBB();//(1)AAA的普通代码块(2)AAA()构造器被调用(3)BBB的普通代码块(4)BBB()构造器被调用
} }class AAA{//父类Object{System.out.println("AAA的普通代码块");}public AAA(){//(1)super()//(2)调用本类的普通代码块System.out.println("AAA()构造器被调用....");}}class BBB extendsAAA {{System.out.println("BBB 的普通代码块...");}public BBB() {//(1)super()//(2)调用本类的普通代码块System.out.println("BBB() 构造器被调用....");} }

package com.zakedu.codeblock_;
public class CodeBlockDetail04 {public static void main(String[] args) {//说明
//(1) 进行类的加载
//1.1 先加载 父类 A021.2 再加载 B02//(2) 创建对象
//2.1 从子类的构造器开始
//new B02();//对象new C02();} }class A02 { //父类
private static int n1 = getVal01();static {System.out.println("A02 的一个静态代码块..");//(2)}{System.out.println("A02 的第一个普通代码块..");//(5)
}public int n3 = getVal02();//普通属性的初始化public static int getVal01() {System.out.println("getVal01");//(1)return 10;}public int getVal02() {System.out.println("getVal02");//(6)return 10;}public A02() {//构造器//隐藏//super()//普通代码和普通属性的初始化......System.out.println("A02 的构造器");//(7)} }class C02 {private int n1 = 100;private static int n2 = 200;private void m1() {}private static void m2() {}static {//静态代码块,只能调用静态成员//System.out.println(n1);错误System.out.println(n2);//ok//m1();//错误m2();}{//普通代码块,可以使用任意成员System.out.println(n1);System.out.println(n2);//okm1();m2();
}  }class B02 extends A02 { //private static int n3 = getVal03();static {System.out.println("B02 的一个静态代码块..");//(4)}public int n5 = getVal04();{System.out.println("B02 的第一个普通代码块..");//(9)}publicstaticintgetVal03(){System.out.println("getVal03");//(3)return 10;}public int getVal04(){System.out.println("getVal04");//(8)return 10;}//一定要慢慢的去品..public B02(){//构造器
//隐藏了
//super()//普通代码块和普通属性的初始化...System.out.println("B02的构造器");//(10)//TODOAuto-generatedconstructorstub} }

4. 单例设计模式

4.1 什么是设计模式

1. 静态方法和属性的经典使用
2. 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索

4.2 什么是单例模式

单例(单个的实例)
1. 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
2. 单例模式有两种方式: 1)饿汉式 2)懒汉式

4.3 单例模式应用实例

演示饿汉式和懒汉式单例模式的实现。
步骤如下:
1) 构造器私有化 =》防止直接new
2) 类的内部创建对象
3) 向外暴露一个静态的公共方法。getInstance
代码:

 package com.zakedu.single_;public class SingleTon01 {public static void main(String[] args) {//  GirlFriend xh = new GirlFriend("小红");//  GirlFriend xb = new GirlFriend("小白");//通过方法可以获取对象GirlFriend instance = GirlFriend.getInstance();System.out.println(instance);GirlFriend instance2 = GirlFriend.getInstance();System.out.println(instance2);System.out.println(instance == instance2);//T//System.out.println(GirlFriend.n1);} }//有一个类, GirlFriend//只能有一个女朋友
class GirlFriend {private String name;
//public static int n1 = 100;//为了能够在静态方法中,返回 gf对象,需要将其修饰为static//對象,通常是重量級的對象, 餓漢式可能造成創建了對象,但是沒有使用.private static GirlFriend gf = new GirlFriend("小红红");//如何保障我们只能创建一个 GirlFriend 对象
//步骤[单例模式-饿汉式]//1. 将构造器私有化
//2. 在类的内部直接创建对象(该对象是static)//3. 提供一个公共的static方法,返回 gf对象
private GirlFriend(String name) {System.out.println("構造器被調用.");this.name = name;}public static GirlFriend getInstance() {return gf;}@Overridepublic String toString() {return "GirlFriend{" +"name='" + name + '\' +'}';} }
package com.zakedu.single_;/*** 演示懶漢式的單例模式
*/public class SingleTon02 {public static void main(String[] args) {//new Cat("大黃");//System.out.println(Cat.n1);Cat instance = Cat.getInstance();System.out.println(instance);//再次調用getInstanceCat instance2 = Cat.getInstance();System.out.println(instance2);System.out.println(instance == instance2);//T} }//希望在程序運行過程中,只能創建一個Cat對象
//使用單例模式
class Cat {private String name;public static int n1 = 999;private static Cat cat ; //默認是 null//步驟
//1.仍然構造器私有化
//2.定義一個static 靜態屬性對象
//3.提供一個public 的 static 方法,可以返回一個Cat對象
//4.懶漢式,只有當用戶使用getInstance 時,才返回cat對象, 後面再次調用時,會返回上次創建的cat對象
//從而保證了單例
private Cat(String name) {System.out.println("構造器調用...");this.name = name;}public static Cat getInstance() {if(cat == null) {//如果還沒有創建 cat 對象cat = new Cat("小可愛");}return cat;}@Overridepublic String toString() {return "Cat{" +"name='" + name + '\' +'}';} }

4.4 饿汉式VS懒汉式

1. 二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建。
2. 饿汉式不存在线程安全问题,懒汉式存在线程安全问题。
3. 饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题。
4. 在我们javaSE标准类中,java.lang.Runtime就是经典的单例模式。

5. final 关键

5.1 基本介绍

final 可以修饰类、属性、方法和局部变量,
在某些情况下.程序员可能有以下需求,就会使用到final:
1) 当不希望类被继承时,可以用final修饰.
2) 当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰。
        【案例演示:访问修饰符 final 返回类型 方法名】
3) 当不希望类的的某个属性的值被修改,可以用final修饰.
        【案例演示: public final double TAX_RATE=0.08】
4) 当不希望某个局部变量被修改,可以使用final修饰
        【案例演示: final double TAX RATE=0.08】
代码:

 package com.zakedu.final_;public class Final01 {public static void main(String[] args) {E e=newE();//e.TAX_RATE = 0.09;} }//如果我们要求A类不能被其他类继承
//可以使用final 修饰 A类
final class A { }//class B extends A {}class C {//如果我们要求hi不能被子类重写//可以使用final 修饰 hi方法public final void hi() {}}class D extends C {//@Override
// public void hi() {
// }
// System.out.println("重写了 C 类的 hi 方法..");
}//当不希望类的的某个属性的值被修改,可以用final修饰
class E {public final double TAX_RATE = 0.08;//常量
}//当不希望某个局部变量被修改,可以使用final修饰
class F {public void cry() {//这时,NUM 也称为 局部常量final double NUM = 0.01;//NUM = 0.9;System.out.println("NUM=" + NUM);} }

5.2 final 使用注意事项

1) final修饰的属性又叫常量,一般用XX XX X来命名
2) final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一【选择一个位置赋初值即可】:
        1.定义时:如public final double TAX_RATE=0.08;
        2.在构造器中
        3.在代码块中。
3) 如果final修饰的属性是静态的,则初始化的位置只能是
        1.定义时  2.在静态代码块不能在构造器中赋值。
4) final类不能继承,但是可以实例化对象。
5) 如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承。
代码:

package com.zakedu.final_;public class FinalDetail01 {public static void main(String[] args) {CC cc =new CC();new EE().cal();} }class AA{/*1. 定义时:如 publicfinal doubleTAX_RATE=0.08;2. 在构造器中
3. 在代码块中
*/public final double TAX_RATE = 0.08;//1.定义时赋值public final double TAX_RATE2 ;public final double TAX_RATE3 ;public AA() {//构造器中赋值TAX_RATE2= 1.1;}{//在代码块赋值TAX_RATE3= 8.8;} }class BB {
/*
如果final 修饰的属性是静态的,则初始化的位置只能是
1 定义时 2 在静态代码块 不能在构造器中赋值。
*/public static final double TAX_RATE = 99.9;public static final double TAX_RATE2 ;static {TAX_RATE2= 3.3;}}//final 类不能继承,但是可以实例化对象final class CC { }//如果类不是final 类,但是含有final方法,则该方法虽然不能重写,但是可以被继承 即,仍然遵守继承的机制.class DD {public final void cal() {//如果类不是final 类,但是含有final方法,则该方法虽然不能重写,但是可以被继承System.out.println("cal()方法");} }class EE extends DD { }

6) 一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法。
7) final不能修饰构造方法(即构造器)
8) final和static往往搭配使用,效率更高,不会导致类加载.底层编译器做了优化处理。
class Demo{
        public static final int i=16; 
        static{
        System.out.println("zak"); } }
9) 包装类(Integer,Double,Float,Boolean等都是final),String也是final类。
代码:

 packagecom.zakedu.final_;public class FinalDetail02{public static void main(String[]args){System.out.println(BBB.num);//包装类,String是final类,不能被继承
} }//final和static往往搭配使用,效率更高,不会导致类加载.底层编译器做了优化处理
class BBB{public final static int num = 10000;static{System.out.println("BBB静态代码块被执行");}
}final class AAA{//一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法
//public final void cry(){}}

6. 抽象类

6.1 抽象类的介绍

1) 用abstract关键字来修饰一个类时.这个类就叫抽象类
        访问修饰符 abstract 类名{ }
2) 用abstract关键字来修饰一个方法时,这个方法就是抽象方法
        访问修饰符 abstract 返回类型 方法名(参数列表); //没有方法体
3) 抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类()
4) 抽象类,是考官比较爱问的知识点,在框架和设计模式使用较多

6.2 抽象类使用的注意事项

1) 抽象类不能被实例化
2) 抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法
3) 一旦类包含了abstract方法,则这个类必须声明为abstract
4) abstract只能修饰类和方法,不能修饰属性和其它的。
代码:

 package com.zakedu.abstract_;public class AbstractDetail01 {public static void main(String[] args) {//抽象类,不能被实例化//new A();} }//抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法//,还可以有实现的方法。
abstract class A {public void hi() {System.out.println("hi");} }//一旦类包含了abstract 方法,则这个类必须声明为abstractabstract class B {public abstract void hi();}//abstract 只能修饰类和方法,不能修饰属性和其它的
class C {// public abstract int n1 = 1;}

8) 抽象方法不能使用private、final和 static来修饰,因为这些关键字都是和重写相违背的。
代码:

 package com.zakedu.abstract_;public class AbstractDetail02 {public static void main(String[] args) {System.out.println("hello");} }
//抽象方法不能使用private、final 和 static 来修饰,因为这些关键字都是和重写相违背的
abstract class H {public  abstract void hi();//抽象方法}//如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类
abstract class E {public abstract void hi();}abstract class F extends E {}class G extends E {@Overridepublic void hi() { //这里相等于 G 子类实现了父类E的抽象方法,所谓实现方法,就是有方法体
} }//抽象类的本质还是类,所以可以有类的各种成员
abstract class D {public int n1 = 10;public static String name = "zak";public void hi() {System.out.println("hi");}public abstract void hello();public static void ok() {System.out.println("ok");} }

7. 抽象类最佳实践-模板设计模式

7.1 基本介绍

        抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
模板设计模式能解决的问题:
1) 当功能内部一部分实现是确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
2) 编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式。

7.2 最佳实践

需求:
1) 有多个类,完成不同的任务job
2) 要求统计得到各自完成任务的时间
java编程建议:
1.先用最容易想到的方法-》代码实现        2.分析问题,提出使用模板设计模式

代码:

 packagecom.zakedu.abstract_;abstract public class Template{ //抽象类-模板设计模式public abstract void job(); //抽象方法public void calculateTime(){ //实现方法,调用job方法//得到开始的时间long start = System.currentTimeMillis();job();//动态绑定机制//得的结束的时间long end = System.currentTimeMillis();System.out.println("任务执行时间"+(end-start));} }
 packagecom.zakedu.abstract_;public class AA extends Template{//计算任务//1+....+800000@Overridepublic void job(){//实现Template的抽象方法joblong num=0;for(longi=1;i<=800000;i++){num +=i;} }//publicvoidjob2(){// 得到开始的时间
// long start = System.currentTimeMillis();// long num =0;
//for (long i = 1; i <= 200000; i++) {
// num += i;
// }//得的结束的时间
// long end = System.currentTimeMillis();
// System.out.println("AA 执行时间 " + (end- start));
// } 
}
 package com.zakedu.abstract_;public class BB extends Template{public void job() {//这里也去,重写了 Template 的 job 方法long num = 0;for (long i = 1; i <= 80000; i++) {num *= i;} } }
package com.zakedu.abstract_;public class TestTemplate {public static void main(String[] args) {AA aa = new AA();aa.calculateTime(); //这里还是需要有良好的 OOP 基础,对多态BB bb = new BB();bb.calculateTime();} }

8. 接口

8.1 基本介绍

8.2 注意事项

代码:

packagecom.zakedu.interface_;public class InterfaceDetail01{public static void main(String[]args){//new IA();} }//1.接口不能被实例化
//2.接口中所有的方法是 public方法, 接口中抽象方法,可以不用abstract 修饰
//3.一个普通类实现接口,就必须将该接口的所有方法都实现,可以使用alt+enter来解决
//4.抽象类去实现接口时,可以不实现接口的抽象方法
interface IA {void say();//修饰符 public protected 默认 privatevoid hi();}class Cat implements IA{@Overridepublic void say() {}@Overridepublic void hi() {} }abstract class Tiger implements IA {}

代码:

packagecom.zakedu.interface_;public class InterfaceDetail02{public static void main(String[]args){//证明接口中的属性,是public static finalSystem.out.println(IB.n1);//说明n1就是static//IB.n1=30;说明n1是final} }interface IB{//接口中的属性,只能是final的,而且是publicstaticfinal修饰符int n1 = 10; //等价publicstaticfinalintn1=10;void hi();}interfaceIC{void say();} 
//接口不能继承其它的类,但是可以继承多个别的接口
interface ID extends IB,IC {}//接口的修饰符 只能是 public 和默认,这点和类的修饰符是一样的
interface IE{ }//一个类同时可以实现多个接口
class Pig implements IB,IC {@Overridepublic void hi() {}@Overridepublic void say() {} }

练习:

8.3 实现接口vs继承类

代码:

packagecom.zakedu.interface_;public class ExtendsVsInterface{public static void main(String[]args){LittleMonkey wuKong = new LittleMonkey("悟空");wuKong.climbing();wuKong.swimming();wuKong.flying();} }//猴子
class Monkey{
private String name;public Monkey(String name) {this.name = name;}public void climbing() {System.out.println(name + " 会爬树...");}public String getName() {return name;} }//接口
interface Fishable {void swimming();}interface Birdable {void flying();}//继承
//小结: 当子类继承了父类,就自动的拥有父类的功能
//如果子类需要扩展功能,可以通过实现接口的方式扩展.
//可以理解 实现接口 是 对java 单继承机制的一种补充.class LittleMonkey extends Monkey implements Fishable,Birdable {public LittleMonkey(String name) {super(name);}@Overridepublic void swimming() {System.out.println(getName() + " 通过学习,可以像鱼儿一样游泳...");}@Overridepublic void flying() {System.out.println(getName() + " 通过学习,可以像鸟儿一样飞翔...");} }

8.4 接口的多态特性

代码:

package com.zakedu.interface_;public class InterfacePolyParameter{public static void main(String[]args){//接口的多态体现//接口类型的变量if01可以指向实现了IF接口类的对象实例IF if01 = new Monster();if01 = new Car();//继承体现的多态
//父类类型的变量a可以指向继承AAA的子类的对象实例AAA a=new BBB();a = new CCC();} }
interface IF{ }class Monster implements IF{}class Car implements IF{}class AAA{ }class BBB extends AAA{ }class CCC extends AAA{ }
package com.zakedu.interface_;public class InterfacePolyArr{publicstaticvoidmain(String[]args){//多态数组->接口类型数组Usb[ ] usbs = new Usb[2];usbs[0] = new Phone_();usbs[1] = newCamera_();/*
给Usb数组中,存放Phone和相机对象,Phone类还有一个特有的方法call(),
请遍历Usb数组,如果是Phone对象,除了调用Usb接口定义的方法外,
还需要调用Phone特有方法call*/for(inti=0;i<usbs.length;i++){usbs[i].work();//动态绑定..//和前面一样,我们仍然需要进行类型的向下转型if(usbs[i] instanceof Phone_) {//判断他的运行类型是 Phone_((Phone_) usbs[i]).call();}} } }interface Usb{void work();}class Phone_ implements Usb {public void call() {System.out.println("手机可以打电话...");}@Overridepublic void work() {}System.out.println("手机工作中...");}class Camera_ implements Usb {@Override
public void work(){System.out.println("相机工作中...");} }
 package com.zakedu.interface_;/***演示多态传递现象
*/public class InterfacePolyPass{public static void main(String[]args){//接口类型的变量可以指向,实现了该接口的类的对象实例IG ig = new Teacher();//如果IG继承了IH接口,而Teacher类实现了IG接口
//那么,实际上就相当于Teacher类也实现了IH接口.//这就是所谓的接口多态传递现象.IH ih = new Teacher();} }interface IH{void hi();}interface IG extends IH{}class Teacher implements IG{@Overridepublic void hi(){} }

9. 内部类

如果定义类在局部位置(方法中/代码块):(1) 局部内部类 (2) 匿名内部类
定义在成员位置 (1) 成员内部类 (2) 静态内部类

9.1 基本介绍

        一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。是我们类的第五大成员【思考:类的五大成员是哪些?[属性、方法、构造器、代码块、内部类]】,内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系,注意:内部类是学习的难点,同时也是重点,后面看底层源码时,有大量的内部类.

9.2 基本语法

9.3 内部类的分类

定义在外部类局部位置上(比如方法内):
1) 局部内部类(有类名)
2) 匿名内部类(没有类名,重点!!!!!!!!)

定义在外部类的成员位置上:
1) 成员内部类(没用static修饰)
2) 静态内部类(使用static修饰)

9.3.1 局部内部类的使用

代码:

 package com.zakedu.innerclass;/*** 演示局部内部类的使用
*/public class LocalInnerClass {//public static void main(String[] args) {//演示一遍Outer02 outer02 = new Outer02();outer02.m1();System.out.println("outer02 的 hashcode=" + outer02);} }class Outer02 {//外部类private int n1 = 100;private void m2() {System.out.println("Outer02 m2()");}//私有方法
public void m1() {//方法//1.局部内部类是定义在外部类的局部位置,通常在方法//3.不能添加访问修饰符,但是可以使用final 修饰//4.作用域 : 仅仅在定义它的方法或代码块中
final class Inner02 {//局部内部类(本质仍然是一个类)//2.可以直接访问外部类的所有成员,包含私有的
private int n1 = 800;public void f1() {//5. 局部内部类可以直接访问外部类的成员,比如下面 外部类n1 和 m2()//7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,//   使用 外部类名.this.成员)去访问//  解读 Outer02.this 本质就是外部类的对象, 即哪个对象调用了m1,Outer02.this就是哪个对象System.out.println("n1=" + n1 + " 外部类的 n1=" + Outer02.this.n1);System.out.println("Outer02.this hashcode=" + Outer02.this);m2();} }//6. 外部类在方法中,可以创建Inner02对象,然后调用方法即可
Inner02 inner02 = new Inner02();inner02.f1();} }

9.3.2 匿名内部类的使用(重要!!!!!!!)

代码:

package com.zakedu.innerclass;/*** 演示匿名内部类的使用
*/public class AnonymousInnerClass {public static void main(String[] args) {Outer04 outer04 = new Outer04();outer04.method();} }class Outer04 { //外部类private int n1 = 10;//属性public void method() {//方法//基于接口的匿名内部类//解读//1.需求: 想使用IA接口,并创建对象//2.传统方式,是写一个类,实现该接口,并创建对象//3.需求是 Tiger/Dog 类只是使用一次,后面再不使用//4. 可以使用匿名内部类来简化开发//5. tiger 的编译类型 ?IA//6. tiger 的运行类型 ? 就是匿名内部类 Outer04$1/*我们看底层 会分配 类名 Outer04$1class Outer04$1 implements IA {@Overridepublic void cry() {System.out.println("老虎叫唤...");} }*///7. jdk 底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1实例,并且把地址//返回给 tiger//8. 匿名内部类使用一次,就不能再使用IA tiger = new IA() {@Overridepublic void cry() {System.out.println("老虎叫唤...");} };System.out.println("tiger 的运行类型=" + tiger.getClass());tiger.cry();tiger.cry();tiger.cry();// IAtiger = new Tiger();
// tiger.cry();
// 演示基于类的匿名内部类
// 分析
//1. father 编译类型 Father//2. father 运行类型 Outer04$2//3. 底层会创建匿名内部类
/*class Outer04$2 extends Father{@Overridepublic void test() {System.out.println("匿名内部类重写了 test 方法");}}*///4. 同时也直接返回了 匿名内部类 Outer04$2的对象
//5. 注意("jack") 参数列表会传递给 构造器
Father father = new Father("jack"){@Overridepublic void test() {System.out.println("匿名内部类重写了 test 方法");
}};System.out.println("father 对象的运行类型=" + father.getClass());//Outer04$2
father.test();//基于抽象类的匿名内部类Animal animal = newAnimal(){@Override
void eat() {System.out.println("小狗吃骨头...");} };animal.eat();} }interface IA {//接口public void cry();}//class Tiger implements IA {//}//@Override
// public void cry() {
// }
// System.out.println("老虎叫唤...");
// class Dog implements IA{
// @Override//public void cry() {
// System.out.println("小狗汪汪...");//}class Father {//类public Father(String name) {//构造器System.out.println("接收到 name=" + name);}public void test() {//方法
}}abstract class Animal { //抽象类abstract void eat();}

代码:

 package com.zakedu.innerclass;public class AnonymousInnerClassDetail {public static void main(String[] args) {Outer05 outer05 = new Outer05();outer05.f1();//外部其他类---不能访问----->匿名内部类System.out.println("main outer05 hashcode=" + outer05);} }
class Outer05 {private int n1 = 99;public void f1() {//创建一个基于类的匿名内部类//不能添加访问修饰符,因为它的地位就是一个局部变量//作用域 : 仅仅在定义它的方法或代码块中
Person p = new Person(){private int n1 = 88;@Overridepublic void hi() {//可以直接访问外部类的所有成员,包含私有的//如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,//默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问System.out.println("匿名内部类重写了 hi 方法 n1=" +n1 +" 外部内的n1="+Outer05.this.n1 );//Outer05.this 就是调用 f1 的 对象System.out.println("Outer05.this hashcode=" + Outer05.this);} };p.hi();//动态绑定, 运行类型是 Outer05$1//也可以直接调用, 匿名内部类本身也是返回对象// class 匿名内部类 extends Person {}// new Person(){
// @Override
// public void hi() {//System.out.println("匿名内部类重写了 hi 方法,哈哈...");
// }
// @Override
// public void ok(String str) {
// super.ok(str);
// }
// }.ok("jack");} }class Person {//类public void hi() {System.out.println("Person hi()");}public void ok(String str) {System.out.println("Personok()"+str);} }//抽象类/接口...

9.3.3 匿名内部类的最佳实践

当做实参直接传递,简洁高效

package com.zakedu.innerclass;import com.zakedu.abstract_.AA;public class InnerClassExercise01{public static void main(String[]args){//当做实参直接传递,简洁高效f1(newIL(){@Overridepublicvoidshow(){System.out.println("这是一副名画~~...");}});//传统方法f1(newPicture());}
//静态方法,形参是接口类型
public static void f1(IL il){il.show();} }//接口
interfaceIL{voidshow();}//类->实现IL=>编程领域(硬编码)class Picture implements IL{@Overridepublic void show(){System.out.println("这是一副名画XX...");} }

9.3.4 成员内部类的使用

3. 作用域
和外部类的其他成员一样,为整个类体比如前面案例,在外部类的成员方法中创建成员内部类对象,再调用方法。
4. 成员内部类---访问---->外部类成员(比如:属性)  [访问方式:直接访问]
5. 外部类---访问------>成员内部类(说明)    访问方式:创建对象,再访问
6. 外部其他类---访问---->成员内部类
7. 如果外部类和内部类的成员重名时,内部类访问的话。默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
代码:
 

package com.zakedu.innerclass;public class MemberInnerClass01 {public static void main(String[] args) {Outer08 outer08 = new Outer08();outer08.t1();//外部其他类,使用成员内部类的三种方式//解读// 第一种方式// outer08.new Inner08(); 相当于把 new Inner08()当做是 outer08 成员// 这就是一个语法,不要特别的纠结.Outer08.Inner08 inner08 = outer08.new Inner08();inner08.say();// 第二方式 在外部类中,编写一个方法,可以返回 Inner08对象Outer08.Inner08 inner08Instance = outer08.getInner08Instance();inner08Instance.say()
}}class Outer08 { //外部类private int n1 = 10;public String name = "张三";private void hi() {System.out.println("hi()方法...");}
//1.注意: 成员内部类,是定义在外部内的成员位置上
//2.可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员public class Inner08 {//成员内部类private double sal = 99.8;private int n1 = 66;public void say() {//可以直接访问外部类的所有成员,包含私有的
//如果成员内部类的成员和外部类的成员重名,会遵守就近原则.//,可以通过 外部类名.this.属性 来访问外部类的成员System.out.println("n1 = " + n1 + " name = " + name + " 外部类的 n1=" + Outer08.this.n1);hi();} }//方法,返回一个Inner08实例public Inner08 getInner08Instance(){return new Inner08();}//写方法public void t1() {//使用成员内部类
//创建成员内部类的对象,然后使用相关的方法Inner08 inner08 = new Inner08();inner08.say();System.out.println(inner08.sal);} }

9.3.5 静态内部类的使用

说明:静态内部类是定义在外部类的成员位置,并且有static修饰
1. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
2. 可以添加任意访问修饰符(public、 protected、默认、private),因为它的地位就是一个成员。
3. 作用域:同其他的成员,为整个类体
4. 静态内部类---访问---->外部类(比如:静态属性)[访问方式:直接访问所有静态成员]
5. 外部类---访问------>静态内部类访问方式:创建对象,再访问
6. 外部其他类---访问----->静态内部类
7. 如果外部类和静态内部类的成员重名时,静态内部类访问的时,默认遵循就近原则。如果想访问外部类的成员,则可以使用(外部类名.成员)去访问
代码:

 package com.zakedu.innerclass;public class StaticInnerClass01{public static void main(String[]args){Outer10 outer10 = new Outer10();outer10.m1();//外部其他类使用静态内部类//方式1//因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)Outer10.Inner10 inner10 = new Outer10.Inner10();inner10.say();//方式2//编写一个方法,可以返回静态内部类的对象实例.Outer10.Inner10 inner101 = outer10.getInner10();System.out.println("============");inner101.say();Outer10.Inner10 inner10_ = Outer10.getInner10_();System.out.println("************");inner10_.say();} }class Outer10 { //外部类private int n1 = 10;private static String name = "张三";private static void cry() {}//Inner10 就是静态内部类//1. 放在外部类的成员位置//2. 使用static 修饰//3. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员//4. 可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员//5. 作用域 :同其他的成员,为整个类体static class Inner10 {private static String name = "zak";public void say() {//如果外部类和静态内部类的成员重名时,静态内部类访问的时,//默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.成员)System.out.println(name + " 外部类 name= " + Outer10.name);cry();} }public void m1() { //外部类---访问------>静态内部类 访问方式:创建对象,再访问Inner10 inner10 = new Inner10();inner10.say();}public Inner10 getInner10() {return new Inner10();}public static Inner10 getInner10_() {return new Inner10();} }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/681828.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

「Java开发指南」如何用MyEclipse搭建GWT 2.1和Spring?(一)

本教程将指导您如何生成一个可运行的Google Web Toolkit (GWT) 2.1和Spring应用程序&#xff0c;该应用程序为域模型实现了CRUD应用程序模式。在本教程中&#xff0c;您将学习如何&#xff1a; 安装Google Eclipse插件为GWT配置一个项目搭建从数据库表到一个现有的项目GWT编译…

图神经网络的应用领域

本文讲解一下图神经网络&#xff08;GNN&#xff09;在不同领域中的应用场景&#xff0c;包括社交网络分析、推荐系统、生物信息学、交通网络优化等场景。读者在碰到需要解决这些场景下的问题时&#xff0c;记得阅读这本书来寻找思路。 1. 社交网络分析 社交网络通常以图的形…

Elasticsearch的基本使用

Elasticsearch的基本使用 1.基本概念1.1 文档和字段1.2 索引和映射1.3 mysql与elasticsearch对比 2.索引库2.1 es中mapping映射属性2.2.es中索引库的增删改查 3.文档3.1 新增文档3.2 查询文档3.3 删除文档3.4 修改文档3.4.1 全量修改3.4.2 增量修改3.5 总结 4.DSL查询语法4.1 D…

小结3:英语泛读

英语泛读 “泛读求语感”。对一篇材料的仔细研究、不断重复&#xff0c;可以将它消化成自己习惯的一部分。但这样的语感是不够自然的&#xff0c;我可能会蹦出一些别扭的话来&#xff0c;如路上偶遇熟人&#xff0c;“您近来身体是否健全&#xff1f;” 过犹不及&#xff0c;所…

聊天框 - 微信加载历史数据的效果原来这样实现的

原文&#xff1a;https://juejin.cn/post/7337114587123335180?searchId20240509192958AF7D129567F92AD7E083 公众号&#xff1a;程序员白特&#xff0c;欢迎一起交流学习~ 前言 我记得2021年的时候做过聊天功能&#xff0c;那时业务也只限微信小程序 那时候的心路历程是&am…

syncGradle项目时报错Unknown Kotlin JVM target: 22

解决方案1 定位到build.gradle.kts的出问题行&#xff0c;将其注释掉然后把sourceCompatibility行也注释掉重新sync. 这样会自动使用默认兼容的版本 你也可以根据文档手动解决兼容问题2 Configure a Gradle project | Kotlin Documentation (kotlinlang.org) ↩︎ Compatibil…

经典回溯算法之N皇后问题

问题描述&#xff1a; 有一个N*N的棋盘&#xff0c;需要将N个皇后放在棋盘上&#xff0c;保证棋盘的每一行每一列每一左斜列每一右斜列都最多只能有一个皇后。 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如…

什么是虚拟货币?

随着科技的进步&#xff0c;虚拟货币逐渐进入公众视野&#xff0c;其影响深远且复杂。本文将从专业角度分析虚拟货币的发展现状、未来趋势&#xff0c;以及面临的挑战&#xff0c;并尝试提出一些思考。 一、虚拟货币的定义与现状 虚拟货币是一种基于区块链技术的数字资产&…

Golang入门教程(非常详细)从零基础入门到精通,看完这一篇就够了

文章目录 一、golang 简介 1. go 语言特点2. go 语言应用领域3. 使用 go 语言的公司有哪些 二、安装 golang 1. golang 下载安装2. 配置环境变量 三、golang 开发工具 1. 安装 VSCode2. 下载所需插件 四、第一个 golang 应用 1. main 包的含义2. 示例 一、golang 简介 Go 是一…

Pytorch入门—Tensors张量的学习

Tensors张量的学习 张量是一种特殊的数据结构&#xff0c;与数组和矩阵非常相似。在PyTorch中&#xff0c;我们使用张量来编码模型的输入和输出&#xff0c;以及模型的参数。 张量类似于NumPy的ndarrays&#xff0c;只是张量可以在GPU或其他硬件加速器上运行。事实上&#xf…

音转文工具,9.8k star! 【送源码】

我们经常会遇到将音频转为文字的情况&#xff0c;比如在开会时录音的会议纪要、上课时录下的老师讲课内容。虽然网上也有一些在线的工具可以将音频转为文字&#xff0c;但是考虑到数据安全和费用问题&#xff0c;使用起来也不是很方便。 今天了不起给大家介绍一款开源工具——…

#友元函数与友元类

目录 1.概念 2.友元函数 3.友元类 1.概念 友元提供了一种突破封装的方式&#xff0c;有时提供了便利。但是友元会增加耦合度&#xff0c;破坏了封装&#xff0c;所以友元不宜多 用。 友元分为&#xff1a;友元函数和友元类 2.友元函数 友元函数可以直接访问类的私有成员&a…