尚硅谷java面向对象(三)笔记

本文详细探讨了Java中的`static`关键字,包括静态变量、静态方法的使用及注意事项。同时,介绍了单例设计模式的实现,以及代码块(静态和非静态)的执行顺序。此外,还涵盖了`final`和`abstract`关键字的用法,以及接口的应用。这些概念在实际开发中至关重要,理解和掌握它们能提升代码质量和效率。
摘要由CSDN通过智能技术生成

1.static关键字

1.1 问题引入:

当编写一个类时,其实就是在描述其属性和行为,而并没有产生实质上的对象,只能通过new关键字才会产生对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。有时候我们希望无论是否产生对象或无论产生多少对象的情况下,某些特定的数据在内存中只有一份

1.2 static的使用

static可以修饰:属性、方法、代码块、内部类。

1.2.1使用static修饰属性:静态变量(类变量)

  • 非静态变量(实例变量):我们创建了类的多个对象,每个对象都独立拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会影响到其他对象的非静态属性。
  • 静态变量(类变量):我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象中静态变量的修改。

说明:静态变量随着类的加载而加载,因此可以用类名.静态变量的方式调用,也可以用对象调用。
因此静态变量的加载早于对象的创建。
由于类只加载一次,则静态变量在内存中只会存在一份,在方法区的静态域中。

public class StaticTest {
    public static void main(String[] args) {
        Chinese.nation="Ch";
        System.out.println(Chinese.nation);//CH
        Chinese c1=new Chinese();
        c1.name="aa";
        c1.age=18;
        c1.nation="Chinese";
        System.out.println(c1.nation);//Chinese
        Chinese c2=new Chinese();
        c2.nation="UK";
        System.out.println(c1.nation);//UK
    }
}
class Chinese{
    static String nation;
    String name;
    int age;
}

内存解析:
在这里插入图片描述

1.2.2 使用static修饰方法:静态方法

随着类的加载而加载,可以通过类名.方法名调用,也可以通过对象调用。

public class StaticTest {
    public static void main(String[] args) {
        Chinese.nation="Ch";
        Chinese.eat();
        Chinese c2=new Chinese();
        c2.eat();
    }
}
class Chinese{
    static String nation;
    String name;
    int age;
    public static void eat(){
        System.out.println("吃饭饭");
    }
}

静态方法中,只能调用静态的方法或静态的属性,不能调用非静态的。(生命周期的原因,static表示类的加载,此时还没有对象,因此不能调用非静态)
非静态方法中,既能调用静态方法或属性,又能调用非静态的方法或属性。
在静态方法内不能使用this、super关键字。因为这两个关键字使用的前提是要有对象。

1.2.3 在开发中,如何确定一个属性是否要声明为static?

属性是可以被多个对象所共享,不会随着对象的不同而不同。

1.2.4 在开发中,如何确定一个方法是否要声明为static?

操作静态属性的方法通常就设置为静态的,如静态属性的get/set方法。
工具类中的方法,习惯上声明为static的。比如Math、Arrays

1.2.5 main()方法

作为一个程序的入口。
也是一个普通的静态方法
可以作为我们与控制台交互的方式。(如使用Scanner)

public static void main(String[] args){}

如何将控制台获取的数据传给形参:String[] args?
运行时:java 类名 “Tom” “jerry” “123” “true”

2.单例设计模式

**设计模式:**是在大量实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。
**单例设计模式:**采取一定方式保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只能提供一个取得其对象实例的方法。所以首先必须将类的构造器访问权限设置为private,这样就不能用new在类的外部产生对象,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量。所以指向类内部产生的该类对象的变量也必须定义成静态的。
单例的饿汉式实现:

public class singlentonTest {
    public static void main(String[] args) {
        Bank1.getInstance();
    }
}
class Bank1{
	//1.私有化类的构造器
    private Bank1(){}
    //2.内部创建类的对象
    //4.要求此对象也必须声明为静态的
    private static Bank1 instance=new Bank1();
    //3.提供公共的静态方法,返回类的对象
    public static Bank1 getInstance(){
        return instance;
    }
}

单例的懒汉式实现:

public class SingletonTest2 {
    public static void main(String[] args) {
        Order order1=Order.getInstance();
        Order order2=Order.getInstance();
    }
}
class Order{
    //1.私有化类的构造器
    private Order(){}
    //2.声明当前类对象,没有初始化
    //4.此对象也必须声明为static的
    private static Order instance=null;
    //3.声明public、static的返回当前类对象的方法
    public static Order getInstance(){
        if(instance==null)
            instance=new Order();
        return instance;
    }
}

区分饿汉式和懒汉式

  • 饿汉式:
    坏处:对象加载事件过长
    好处: 线程安全
  • 懒汉式:
    好处:延迟对象的创建
    坏处:线程不安全

3.代码块(或初始化块)

作用:初始化类、对象
格式:staic{ }或者{ }
分类:静态代码块,非静态代码块

3.1 静态代码块

public class BlockTest {
    public static void main(String[] args) {
    	String desc1=Person.desc;//输出结果:static
        String desc2=Person.desc;//不执行
        Person p1=new Person();//输出结果:no static
        Person p2=new Person();//输出结果:no static    
    }
}
class Person{
    String name;
    int age;
    static String desc="person";
    static{
    	desc="abc";
        System.out.println("static");
    }
    {
    	age=1;
        System.out.println("no static");
    }
}
  • 内部可以有输出语句。
  • 随着类的加载而执行(调用)。也就是不需要通过“类.方法”的结构,就可以直接调用静态代码块。
  • 只执行一次
  • 可以定义多个静态代码块。如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行。
  • 静态代码块的执行先于非静态代码块
  • 只能调用静态结构

作用:初始化类的信息(静态属性)

3.2 非静态代码块

  • 内部可以有输出语句。
  • 随着对象的创建而执行(调用)。
  • 每创建一个对象,非静态代码块就会执行一次
  • 可以定义多个非静态代码块。如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行。
  • 既可以调用静态结构,又可以调用非静态结构

作用:可以在创建对象时,对对象的属性进行初始化。

3.3 静态代码块、非静态代码块、构造器调用顺序

class Root{
    static {
        System.out.println("Root静态代码块");
    }
    {
        System.out.println("Root非静态代码块");
    }
    public Root(){
        super();
        System.out.println("Root无参构造器");
    }
}
class Mid extends Root{
    static {
        System.out.println("Mid静态代码块");
    }
    {
        System.out.println("Mid非静态代码块");
    }
    public Mid(){
        super();
        System.out.println("Mid无参构造器");
    }
    public Mid(String msg){
        this();
        System.out.println("Mid带参构造器,其参数值:"+msg);
    }
}
class Leaf extends Mid{
    static {
        System.out.println("Leaf静态代码块");
    }
    {
        System.out.println("Leaf非静态代码块");
    }
    public Leaf(){
        super("d-linlin");
        System.out.println("Leaf构造器");
    }
}
public class LeafTest {
    public static void main(String[] args) {
        new Leaf();
        System.out.println("**********");
        new Leaf();
    }
}

执行结果:
在这里插入图片描述
总结:从父到子,静态先行

3.4 属性赋值执行的先后顺序

对属性可以赋值的位置:
1.默认初始化
2.显式初始化
3.构造器初始化
4.有了对象后,可以通过“对象.属性”或“对象.方法”的方式进行赋值
5.在代码块中赋值

①–>②/⑤–>③–>④
2和5的顺序是按照编写代码的顺序执行

4.final关键字

final:最终的、最后的
final可以修饰类、方法、变量

4.1 final修饰类

final class FinalA{}

被final修饰的类就不能被其他类继承
如:String类、System类、StringBuffer类

4.2 final修饰方法

public final void eat(){}

被final修饰的方法不能被重写

public final native Class<?>getClass();

native表示接下来调用底层的c或c++代码

4.3 final修饰变量

此时的“变量”就是一个常量了

4.3.1 final修饰属性

可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化

final class FinalA{
    final int width=1;//显式初始化
    final int left;
    final int right;
    {
        left=1;//代码块赋值
    }
    public FinalA(){
        right=1;//构造器中赋值
    }
    public FinalA(int n){
        right=n;
    }
}

如果在构造器中赋值,且有多个构造器,必须在每个构造器中都给final变量赋值。一旦有某个构造器没有给其赋值,就会认为final变量没有赋值,就会报错。
不能通过函数给final属性赋值。原因:当调用构造器时,表示一个对象就创建好了,此时在内存中也就加载了属性,而final属性此时没有被赋值,因为还没有调用函数,因此不能通过函数给final属性赋值。

4.3.2 final修饰局部变量

public class FinalTEst {
    public static void main(String[] args) {
        FinalA a=new FinalA();
        a.show(2);
        a.show(1);
    }
}
final class FinalA{
    public void show(){
        final int num=10;
        num++;//错误
    }
    public void show(final int num){
        num+=5;//错误
        System.out.println(num);
    }
}

尤其使用final修饰形参时,表明此形参是一个常量,当我们调用此方法时,给常量形参赋一个实参,一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。

4.4 static final

用来修饰属性:全局常量
用来修饰

5.abstract关键字

可以修饰类和方法

abstract class Person{
    String name;
    int age;
    public Person(){};
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    public void eat(){
        System.out.println("吃饭");
    }
    //抽象方法
    public abstract void walk();
}
class Man extends Person{
    public void walk(){}
}

5.1 抽象类

抽象父类不能创建对象,即不能实例化。
抽象父类一定有构造器,虽然抽象父类自己不能调用,但是子类一定会调用。

5.2 抽象方法

  • 抽象方法只有方法声明,没有方法体,所以抽象方法不应该被对象调用,也就是此类不能创建对象,因此包含抽象方法的类必须是抽象类。但是抽象类可以没有抽象方法。
  • 若子类不是抽象类,则子类必须重写父类(包括所有间接父类)所有的抽象方法。
  • 若子类是抽象类,可以不用重写父类所有抽象方法。

5.3 abstract注意点

abstract不能修饰属性、构造器、私有方法、静态方法、final的方法、final的类

6.接口

通过接口可得到多重继承的效果。
一个类可以实现多个接口。
在这里插入图片描述
在这里插入图片描述

6.1接口的使用

①接口用interface来定义。
②如何定义接口:定义接口中的成员。

  • 在JDK7之前,只能定义全局常量(public static final的,但是书写时可以省略)和抽象方法(public abstract的,也可省略不写)。
  • JDK8:除了定义全局常量和抽象方法,还可以定义静态方法、默认方法。
    ③接口中不能定义构造器!意味着接口不能实例化(创建对象)
    ④Java开发中,接口通过让类去实现(implements)的方式来使用
    ⑤如果实现类覆盖了接口中所有抽象方法,则此实现类就可以实例化。
    但如果实现类没有覆盖接口中所有抽象方法,则此实现类仍为一个抽象类实例化。
    ⑥Java类可以实现多个接口—>弥补了只能单继承的缺点
    ⑦接口与接口之间可以继承,且可以多继承。
    ⑧接口的使用体现了多态性。
    ⑨接口实际上可以看做是一种规范。

定义全局变量:

public class Inter {
    public static void main(String[] args) {
        System.out.println(Flyable.MAX_SPEED);
        System.out.println(Flyable.MIN_SPEED);
    }
}
interface Flyable{
    public static final int MAX_SPEED =7900;
    int MIN_SPEED =1;//省略了public static final
}

定义抽象方法:

public class Inter {
    public static void main(String[] args) {
    }
}
interface Flyable{
    public abstract void fly();
    void stop();//省略了public abstract
}

一个类实例化一个接口:

public class Inter {
    public static void main(String[] args) {
    }
}
interface Flyable{
    public abstract void fly();
    void stop();//省略了public abstract
}
class Plane implements Flyable{

    @Override
    public void fly() {
        System.out.println("起飞");
    }

    @Override
    public void stop() {
        System.out.println("停机  ");
    }
}

一个类实例化多个接口

interface Flyable{
    public abstract void fly();
    void stop();//省略了public abstract
}
interface Attackable{
    void attack();
}
class bullet implements Attackable,Flyable{
    @Override
    public void fly() {
        System.out.println("射击");
    }

    @Override
    public void stop() {
        System.out.println("停止");
    }

    @Override
    public void attack() {
        System.out.println("攻击");
    }
}

一个子类继承父类,且实例化多个接口
格式:class B extends A implements C,D{}

interface Flyable{
    public abstract void fly();
    void stop();//省略了public abstract
}
interface Attackable{
    void attack();
}
class bullet extends Object implements Attackable,Flyable{
    @Override
    public void fly() {
        System.out.println("射击");
    }

    @Override
    public void stop() {
        System.out.println("停止");
    }

    @Override
    public void attack() {
        System.out.println("攻击");
    }
}

接口间继承,且子类实现多个接口,包括此继承后的接口

public class Inter {
    public static void main(String[] args) {
    }
}
interface Flyable{
    public abstract void fly();
    void stop();//省略了public abstract
}
interface Attackable{
    void attack();
}
interface AA{
    void method1();
}
interface BB{
    void method2();
}
interface CC extends AA,BB{}
class bullet extends Object implements Attackable,Flyable,CC{
    @Override
    public void fly() {
        System.out.println("射击");
    }

    @Override
    public void stop() {
        System.out.println("停止");
    }

    @Override
    public void attack() {
        System.out.println("攻击");
    }

    @Override
    public void method1() {}

    @Override
    public void method2() {}
}

如何调用接口的方法(接口的多态性)

public class Inter {
    public static void main(String[] args) {
        Computer com=new Computer();
        Flash f=new Flash();
        com.transferData(f);
    }
}
class Computer{
    public void transferData(USB usb){
        usb.start();
        usb.stop();
    }
}
interface USB{
    void start();
    void stop();
}
class Flash implements USB{

    @Override
    public void start() {
        System.out.println("U盘开启");
    }

    @Override
    public void stop() {
        System.out.println("U盘停止");
    }
}
class Printer implements USB{

    @Override
    public void start() {
        System.out.println("打印机开始工作");
    }

    @Override
    public void stop() {
        System.out.println("打印机停止工作");
    }
}

6.2接口的应用:代理模式

在这里插入图片描述
在这里插入图片描述

package cn.demo.day.practice;

/**
 * @description:
 * @author: d-linlin
 * @time: 2021/11/17
 */
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{

    @Override
    public 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("联网之前的检查工作");
    }
    @Override
    public void browse() {
        check();
        work.browse();
    }
}

6.3接口练习

在这里插入图片描述

package cn.demo.day.practice;
/**
 * @description:
 * @author: d-linlin
 * @time: 2021/11/17
 */
public class InterfaceTest {
    public static void main(String[] args) {
        ComparableCircle c1=new ComparableCircle(3.1);
        ComparableCircle c2=new ComparableCircle(3.2);
        int compareValue=c1.compareTo(c2);
        if(compareValue==0){
            System.out.println("c1,c2一样大");
        }else if(compareValue<0){
            System.out.println("c2大");
        }else{
            System.out.println("c1大");
        }
    }
}
interface CompareObject{
    //若返回值是0,代表相等;若为正数,代表当前对象大;负数代表当前对象小
    public int compareTo(Object o);

}
class Circle{

    private double redius;
    public Circle(double redius){
        this.redius=redius;
    }
    public double getRedius() {
        return redius;
    }

    public void setRedius(double redius) {
        this.redius = redius;
    }
}
class ComparableCircle extends Circle implements CompareObject{

    public ComparableCircle(double radius){
        super(radius);
    }
    @Override
    public int compareTo(Object o) {
        if(this==o)return 0;
        if(o instanceof ComparableCircle){
            ComparableCircle c=(ComparableCircle) o;
            //return (int)(this.getRedius()-c.getRedius());
            if(this.getRedius()>c.getRedius())return 1;
            else if(this.getRedius()<c.getRedius())return -1;
            else{
                return 0;
            }
        }else{
            //return 0;
            throw new RuntimeException("传入的数据类型不匹配");
        }
    }
}

6.4 Java8中接口的新特性

除了定义全局常量和抽象方法外,还可以定义静态方法(public static)、默认方法(public default,public可省略)
接口中定义的静态方法,只能通过接口去调用。
接口中的默认方法,可以通过实现类的对象去调用。
如果实现类重写了接口中的默认方法,仍然调用重写后的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值