JavaSE---05面向对象(下)
05 面向对象(下)
5.1 关键字:static
5.1.1 概念及使用
概念
1.static:静态的。 2.static 可以用来修饰:属性、方法、代码块、内部类。3.使用 static 修饰属性:静态变量(或类变量)。3.1 属性:是否使用 static 修饰,又分为:静态属性 VS 非静态属性(实例变量)实例变量:我们创建了类的多个对象,每个对象都独立的拥有了一套类中的非静态属 性。当修改其中一个非静态属性时,不会导致其他对象中同样的属性值的修饰。静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过静态变量去修改某一个变量时,会导致其他对象调用此静态变量时,是修改过的。3.2 static 修饰属性的其他说明:① 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用。② 静态变量的加载要早于对象的创建。③ 由于类只会加载一次,则静态变量在内存中也只会存在一次。存在方法区的静态域中。④ 类变量 实例变量类 yes no对象 yes yes通俗说
一套三室一厅一厨一卫的房子出租,三间卧室相当于类的三个实例化对象,其中有各自的属性如床、柜子、桌子等,彼此之前互不干扰,而厕所和厨房就像是static所修饰的属性,是所有人共用的,一个人修改了其余人的也更改。
示例
public class StaticTest {public static void main(String[] args) {Chinese.nation = "中国";//实例化前就有了Chinese c1 = new Chinese();c1.name = "姚明";c1.age = 40;c1.nation = "CHN";Chinese c2 = new Chinese();c2.name = "马龙";c2.age = 30;c2.nation = "CHINA";System.out.println(c1.nation); //CHINA,二者共用的nation//编译不通过 // Chinese.name = "张继科"; } } //中国人 class Chinese{String name;int age;static String nation; }5.1.2 类变量的内存解析
5.1.3 static修饰方法
概念
1.使用 static 修饰方法:静态方法① 随着类的加载而加载,可以通过"类.静态方法"的方式调用② 静态方法 非静态方法类 yes no对象 yes yes③ 静态方法中,只能调用静态的方法或属性!!!非静态的方法中,可以调用所有的方法或属性 2.static 注意点:2.1 在静态的方法内,不能使用 this 关键字、super 关键字2.2 关于静态属性和静态方法的使用,从生命周期的角度去理解。3.开发中,如何确定一个属性是否需要声明 static 的?- 属性是可以被多个对象所共享的,不会随着对象的不同而不同的。- 类中的常量也常常声明为 static开发中,如何确定一个方法是否要声明为 static 的?- 操作静态属性的方法,通常设置为 static 的- 工具类中的方法,习惯上声明为 static 的。比如:Math、Arrays、Collections5.1.4 题目示例
//static 关键字的应用 public class CircleTest {public static void main(String[] args) {Circle c1 = new Circle();Circle c2 = new Circle();Circle c3 = new Circle(3.4);System.out.println("c1 的 ID:" + c1.getId());//1001System.out.println("c2 的 ID:" + c2.getId());//1002System.out.println("c3 的 ID:" + c3.getId());//1003System.out.println("创建圆的个数: " + Circle.getTotal());//3} }class Circle{private double radius;private int id; //需要自动赋值public Circle(){id = init++;total++;}public Circle(double radius){this();this.radius = radius;}private static int total;//记录创建圆的个数private static int init = 1001;//static 声明的属性被所有对象所共享public double findArea(){return 3.14 * radius * radius;}public double getRadius() {return radius;}public void setRadius(double radius) {this.radius = radius;}public int getId() {return id;}public static int getTotal() {return total;} }5.1.5 单例设计模式
概念
1.所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例
2.如何实现?
饿汉式 VS 懒汉式
3.区分饿汉式和懒汉式。
饿汉式:坏处:对象加载时间过长。
好处:饿汉式是线程安全的。
懒汉式:好处:延迟对象的创建。
坏处:目前的写法,会线程不安全。—》到多线程内容时,再修改
代码示例1—饿汉式
public class SingletonTest {public static void main(String[] args) {Bank bank1 = Bank.getInstance();Bank bank2 = Bank.getInstance();System.out.println(bank1 == bank2);//true,因为只有一个对象} }//单例的饿汉式 class Bank{//1.私有化类的构造器private Bank(){ }//2.内部创见类的对象//4.要求此对象也必须声明为静态的private static Bank instance = new Bank();//3.提供公共的静态的方法,返回类的对象。public static Bank getInstance(){return instance;} }代码示例2—懒汉式
public class SingletonTest2 {public static void main(String[] args) {Order order1 = Order.getInstance();Order order2 = Order.getInstance(); System.out.println(order1 == order2);//true} } class Order{//1.私有化类的构造器private Order(){ }//2.声明当前类对象,没有初始化。//此对象也必须声明为 static 的private static Order instance = null;//3.声明 public、static 的返回当前类对象的方法public static Order getInstance(){if(instance == null){instance = new Order(); }return instance;} }5.2 main()方法的语法(了解)
使用说明
1.main()方法作为程序的入口;
2.main()方法也是一个普通的静态方法
3.main()方法也可以作为我们与控制台交互的方式。(之前,使用 Scanner)
5.3 代码块(类的成员之四)💛
5.3.1 代码块概念
概念
1.代码块的作用:用来初始化类、对象的
2.代码块如果有修饰的话,只能使用static
3.分类:静态代码块 vs 非静态代码块
-
静态代码块
- 内部可以有输出语句
- **随着类的加载而执行**,而且**只执行一次**
- 作用:初始化类的信息
- 如果一个类中,定义了多个静态代码块,则按照声明的先后顺序执行
- 静态代码块的执行,**优先于非静态**代码块的执行
- 静态代码块内**只能调用静态的属性、静态的方法**,不能调用非静态的结构
-
非静态代码块
-
内部可以有输出语句
-
随着对象的创建而执行
-
每创建一个对象,就执行一次非静态代码块。
-
作用:可以在创建对象时,对对象的属性等进行初始化。
-
如果一个类中,定义了多个非静态代码块,则按照声明的先后顺序执行
-
非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法。
-
5.3.2 变量赋值执行顺序💛
构造器、静态、非静态的先后顺序
见Day5中的Son.java和LeafTest.java中的例子
静态块–>非静态块–>构造器
属性赋值先后循序
对属性可以赋值的位置: ①默认初始化 ②显式初始化 / ⑤在代码块中赋值 //看谁先谁后 ③构造器中初始化 ④有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值。执行的先后顺序:① - ② / ⑤ - ③ - ④子类父类内部执行顺序
父类静态代码块 ->子类静态代码块 ->父类非静态代码块 -> 父类构造函数 -> 子类非静态代码块 -> 子类构造函数。
5.4 关键字:final
概念
- final:最终的
-
final可以用来修饰的结构:类、方法、变量
-
final用来修饰一个类:此类不能被其他类所继承。
- 比如:String类、System类、StringBuffer类
-
final修饰一个方法:final标记的方法不能被子类重写。
- 比如:Object类中的getClass()。
-
final用来修饰变量:此时的"变量"(成员变量或局部变量)就是一个常量。名称大写,且只能被赋值一次。
-
final修饰属性,可以赋值的位置有:显式初始化、代码块中初始化、构造器中初始化(每个都要赋值)
-
final修饰局部变量:尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。
-
-
static final 用来修饰:全局常量
代码示例
final int WIDTH = 0; final int LEFT; final int RIGHT;{LEFT = 1; }public FinalTest(){RIGHT = 2; }public FinalTest(int n){RIGHT = n; }5.5 抽象类与抽象方法
5.5.1 概念
概念
-
abstract:抽象的
-
abstract 可以用来修饰的结构:类、方法
-
abstract 修饰类:抽象类
-
此类不能实例化
-
抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化全过程)
-
开发中,都会提供抽象类的子类,让子类对象实例化,实现相关的操作
-
-
abstract 修饰方法:抽象方法
-
抽象方法,只有方法的声明,没有方法体。public abstract void eat();
-
包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法
-
若子类重写了父类中所有的抽象方法,此子类方可实例化。
若子类没有重写了父类中所有的抽象方法,则此子类也是一个抽象类。
-
-
abstract 使用上的注意点:
-
abstract 不能用来修饰变量、代码块、构造器;
-
abstract 不能用来修饰私有方法、静态方法、final 的方法、final 的类。
-
5.5.2 抽象类的匿名子类
PersonTest类
public class PersonTest {public static void main(String[] args) {method(new Student()); //匿名对象Worker worker = new Worker(); method1(worker); //非匿名的类非匿名的对象method1(new Worker()); //非匿名的类匿名的对象System.out.println("*********************");//创建了一个匿名子类的对象:p //这样如果只造一个对象就没必要新造一Person p = new Person(){ //个类了,这样创建匿名子类更方便@Overridepublic void eat() {System.out.println("吃东西");}@Overridepublic void breath() {System.out.println("呼吸空气");} };method1(p);System.out.println("**********************"); //创建匿名子类的匿名对象method1(new Person(){@Overridepublic void eat() {System.out.println("吃零食");}@Overridepublic void breath() {System.out.println("云南的空气");}});}public static void method1(Person p){p.eat();p.walk();}public static void method(Student s){} }class Worker extends Person{@Overridepublic void eat() {}@Overridepublic void breath() {} }5.5.3 抽象的应用–模板方法设计模式
概念
当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去(写成抽象方法),让子类去实现。
换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现(重写)。这就是一种模板模式。
示例
public class TemplateMethodTest {public static void main(String[] args) {BankTemplateMethod btm = new DrawMoney();btm.process();BankTemplateMethod btm2 = new ManageMoney();btm2.process();} } abstract class BankTemplateMethod {// 具体方法public void takeNumber() {System.out.println("取号排队");}//不确定部分(核心所在)public abstract void transact(); // 办理具体的业务 //钩子方法public void evaluate() {System.out.println("反馈评分");}// 模板方法,把基本操作组合到一起,子类一般不能重写public final void process() {this.takeNumber();this.transact();// 像个钩子,具体执行时,挂哪个子类,就执行哪个子类//的实现代码this.evaluate();} }class DrawMoney extends BankTemplateMethod {public void transact() {System.out.println("我要取款!!!");} }class ManageMoney extends BankTemplateMethod {public void transact() {System.out.println("我要理财!我这里有 2000 万美元!!");} }5.6 接口
5.6.1 概念及特点
概念
一方面,有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java 不支持多重继承。有了接口,就可以得到多重继承的效果。
另一方面,有时必须从几个类中抽取出一些共同的行为特征,而它们之间又没有 is-a 的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、MP3 机、手机、数码相机、移动硬盘等都支持 USB 连接。
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要…则必须能…”的思想。继承是一个"是不是"的关系,而接口实现则是"能不能"的关系。
接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。
特点
使用
接口使用interface来定义。
在 Java 中:接口和类是并列的两个结构
如何去定义两个接口:定义接口中的成员
-
3.1JDK7 及以前:只能定义全局常量和抽象方法
-
全局常量:只能是public static final 的,但是书写时,可以省略不写。
-
抽象方法:只能是public abstract 的
-
-
3.2 JDK8:除了全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)。
接口中不能定义构造器!意味着接口不可以实例化。
Java 开发中,接口通过让类去实现(implements)的方式来使用。
-
如果实现类覆盖了接口中的所有方法,则此实现类就可以实例化。
-
如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
Java 类可以实现多个接口 —>弥补了 Java 单继承性的局限性
格式:class AA extends BB implementd CC,DD,EE
接口与接口之间是继承,而且可以多继承
接口的具体使用,体现多态性。接口的主要用途就是被实现类实现。(面向接口编程)
接口,实际可以看作是一种规范
5.6.2 示例
/** 接口的使用* 1.接口使用上也满足多态性* 2.接口,实际上就是定义了一种规范* 3.开发中,体会面向接口编程!* */ public class USBTest {public static void main(String[] args) {Computer com = new Computer();//1.创建了接口的非匿名实现类的非匿名对象Flash flash = new Flash();com.transferData(flash); //2. 创建了接口的非匿名实现类的匿名对象com.transferData(new Printer());//3. 创建了接口的匿名实现类的非匿名对象USB phone = new USB(){@Overridepublic void start() {System.out.println("手机开始工作");}@Overridepublic void stop() {System.out.println("手机结束工作");} };com.transferData(phone);//4. 创建了接口的匿名实现类的匿名对象com.transferData(new USB(){@Overridepublic void start() {System.out.println("mp3 开始工作");}@Overridepublic void stop() {System.out.println("mp3 结束工作");}});} }class Computer{public void transferData(USB usb){//USB usb = new Flash();多态usb.start(); System.out.println("具体传输数据的细节");usb.stop();} }interface USB{//常量:定义了长、宽void start();void stop(); } class Flash implements USB{@Overridepublic void start() {System.out.println("U 盘开始工作");}@Overridepublic void stop() {System.out.println("U 盘结束工作");} } class Printer implements USB{@Overridepublic void start() {System.out.println("打印机开启工作");}@Overridepublic void stop() {System.out.println("打印机结束工作");} }5.6.3 接口应用-代理模式
代理模式是 Java 开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。
public class NetWorkTest {public static void main(String[] args) {Server server = new Server();ProxyServer proxyServer = new ProxyServer(server);proxyServer.browse();//联网前的检查工作-真实的服务器来访问网络} } interface NetWork{public void browse();} //被代理类 class Server implements NetWork{@Overridepublic void browse() {System.out.println("真实的服务器来访问网络");} } //代理类 class ProxyServer implements NetWork{private NetWork work;public ProxyServer(NetWork work){this.work = work;}public void check(){System.out.println("联网前的检查工作");}@Overridepublic void browse() {check(); work.browse();} }5.6.4 面试题
排错1
interface A {int x = 0; } class B {int x = 1; } class C extends B implements A {public void pX() { // 编译不通过,x 不明确System.out.println(x); // System.out.println(super.x); //1 // System.out.println(A.x);//0}public static void main(String[] args) {new C().pX();} }排错2
interface Playable {void play(); } interface Bounceable {void play(); } interface Rollable extends Playable, Bounceable {Ball ball= new Ball("PingPang"); //省略了 public static final } public class Ball implements Rollable {private String name;public String getName() {return name;}public Ball(String name) {this.name= name;}public void play() {ball = new Ball("Football"); //The final field Rollable.ball cannot be assigned.不能再被赋值System.out.println(ball.getName());} }5.6.5 Java8中关于接口的改进
Java8中除了全局常量和抽象方法之外,还可以定义静态方法、默认方法。
静态方法:使用 static 关键字修饰。可以通过接口直接调用静态方法,并执行其方法体。
默认方法:默认方法使用 default 关键字修饰。可以通过实现类对象来调用。
示例
public class SubClassTest {public static void main(String[] args) {SubClass s = new SubClass(); // s.method1();//调用不了 // SubClass.method1();//调用不了 // 知识点 1:接口中定义的静态方法,只能通过接口来调用。CompareA.method1(); // 知识点 2:通过实现类的对象,可以调用接口中的默认方法。 // 如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法s.method2(); // 知识点 3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法, // 那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。-->类优先原则 // 知识点 4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法, // 那么在实现类没有重写此方法的情况下,报错。-->接口冲突。 // 这就需要我们必须在实现类中重写此方法s.method3();} } class SubClass extends SuperClass implements CompareA,CompareB{public void method2(){System.out.println("SubClass:上海");}public void method3(){System.out.println("SubClass:深圳");}// 知识点 5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法public void myMethod(){method3(); //调用自己定义的重写的方法super.method3(); //调用的是父类中声明的 // 调用接口中的默认方法CompareA.super.method3();CompareB.super.method3();} }public interface CompareA {//静态方法public static void method1() {System.out.println("CompareA:西安");}//默认方法public default void method2(){System.out.println("CompareA:深圳");}default void method3(){System.out.println("CompareA:杭州");} }5.7 内部类(类的成员之五)💛
概念
Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B就是外部类.
内部类的分类:成员内部类(静态、非静态)VS局部内部类(方法内、代码块内、构造器内)
成员内部类
- 作为外部类的成员,
- 可以调用外部类的结构(静态内部类的只能调用静态方法和属性)
- 可以被static修饰
- 可以被4种不同的权限修饰
- 作为一个类,
- 类内可以定义属性、方法、构造器等
- 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
- 可以abstract修饰
关注如下的3个问题
-
如何实例化成员内部类的对象
-
如何在成员内部类中区分调用外部类的结构
-
开发中局部内部类的使用 见《InnerClassTest.java》
示例代码
public class InnerClassTest {public static void main(String[] args) {//创建Dog实例(静态的成员内部类)Person.Dog dog = new Person.Dog();dog.show();//创建Bird实例(非静态的成员内部类) // Person.Bird bird = new Person.Bird();//错误的Person p = new Person();Person.Bird bird = p.new Bird();bird.sing();System.out.println();bird.display("喜鹊");} } class Person{String name = "李雷";int age;public void eat(){System.out.println("人,吃饭");}//静态成员内部类static class Dog{String name;int age;public void show(){System.out.println("卡拉是条狗"); // eat();}}//非静态成员内部类class Bird{String name = "杜鹃";public Bird(){}public void sing(){System.out.println("我是一只猫头鹰");Person.this.eat();//调用外部类的非静态属性eat();System.out.println(age);}public void display(String name){System.out.println(name); //方法的形参System.out.println(this.name); //内部类的属性System.out.println(Person.this.name); //外部类的属性}}public void method(){//局部内部类class AA{ }}//代码块中{//局部内部类class BB{ }}//构造器中public Person(){//局部内部类class CC{}} }局部内部类示例
// 返回一个实现了Comparable接口的类的对象public Comparable getComparable(){// 创建一个实现了Comparable接口的类:局部内部类//方式一: // class MyComparable implements Comparable{ // // @Override // public int compareTo(Object o) { // return 0; // } // // } // // return new MyComparable();//方式二:匿名方式return new Comparable(){@Overridepublic int compareTo(Object o) {return 0;} };}总结
以上是生活随笔为你收集整理的JavaSE---05面向对象(下)的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: LPNMA
- 下一篇: 【Java--面向对象(下)】