面向对象2

面向对象2

1.静态 static关键字

  • 使用范围:在Java类中, 可用static修饰属性、 方法、 代码块、 内部类
  • 被修饰后的成员具备以下特点:
    • 随着类的加载而加载
    • 优先于对象存在
    • 修饰的成员,被所有对象所共享
    • 访问权限允许时,可不创建对象,直接被类调用
  • 类方法,类中使用static修饰的方法
    • 没有对象的实例时,可以用**类名.方法名()**的形式访问由static修饰的类方法。
    • static方法内部只能访问类的static修饰的属性或方法不能访问类的非static的结构
    • 因为不需要实例就可以访问static方法,因此static方法内部不能有this。 (也不能有super ? YES!)
    • static修饰的方法不能被重写

案例:

Chinese类

package com.example.java.day6;/**
 * @User HASEE
 * @Author WeiXu
 * @Createtime 2023/7/24-24-10:14
 * @PACKAGE_NAME com.example.java.day6
 */

/**
 *@ClassName:Chinese
 *@author weixu
 *@date 2023/7/24 10:14
 */
public class Chinese {

    private String name;
    private int age;

    public static String nation = "大中国";

    public void f1() {
        System.out.println("f1");
    }

    public static void f2() {
        System.out.println("f2");
    }


    //自我介绍
    public static void show() {
        //在静态方法中,不能使用this,super
        //静态方法中,只能使用静态变量
        System.out.println("自我介绍" + nation);
        f2();
    }

    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;
    }
}

StaticTest类:

public class StaticTest {
    public static void main(String[] args) {
        Chinese malong = new Chinese();
        Chinese yaoming = new Chinese();
        malong.setName("马龙");
        yaoming.setName("姚明");
        malong.setAge(30);
        System.out.println(Chinese.nation);//大中国 类中原来的静态变量为大中国
        malong.nation = "中国";
        System.out.println(Chinese.nation);//中国 //
        yaoming.nation = "美国";
        System.out.println(Chinese.nation);//美国
        yaoming.setAge(40);
        System.out.println(malong.getName()+" "+malong.getAge()+" "+Chinese.nation);//马龙 30 美国
        //调用静态方法
        Chinese.show();
    }

}

2.单例模式

  • 设计模式:程序在某一个场景的,设计和开发套路,比如围棋和象棋套路
  • 单例模式:要求程序中某一个组件,在程序运行的整个生命周期中,只有一个实例
    • **构造函数私有,**外面的组件不能主动创建这个对象
    • **提供静态方法返回对象实例,**返回的是静态实例(静态的特性),所以只有一个实例

1.饿汉式单例模式

  • 好处:线程安全的
  • 坏处:加载时,时间比较长 (实例在类加载时就被创建。如果实例的初始化过程较为复杂需要执行大量的初始化操作或者依赖其他资源,就会导致类加载的时间较长。)
public class EagerSingleton {
    private EagerSingleton()
    {
        System.out.println("饿汉式单例模式");
    }

    private static EagerSingleton instance = new EagerSingleton();//因为静态的特性只有一份存在方法区,所以这个对象一定只有一个
    public static EagerSingleton getInstance()
    {
        return instance;
    }

}

image.png

2.懒汉式

存在线程安全问题,没有静态初始化

public class LazySingleton {
    private LazySingleton()
    {
        System.out.println("懒汉式单例模式");
    }

    private static LazySingleton instance = null;
    public static   LazySingleton getInstance()
    {
        if (instance == null)
        {
            instance = new LazySingleton();
        }
        return instance;
    }
}

测试:

public class SingletonTest {
    //单例模式
    public static void main(String[] args) {
        //1.饿汉式 好处:线程安全的 坏处:加载时,时间比较长
        EagerSingleton s1 = EagerSingleton.getInstance();
        EagerSingleton s2 = EagerSingleton.getInstance();
        EagerSingleton s3 = EagerSingleton.getInstance();
        //2.懒汉式 存在线程安全问题,没有静态初始化
        LazySingleton s4 = LazySingleton.getInstance();
        LazySingleton s5 = LazySingleton.getInstance();

    }
}

懒汉式线程不安全的原因:

  1. 多线程竞争:在懒汉式单例模式中,当多个线程同时调用 getInstance() 方法,而此时实例尚未创建(instance 为 null),它们会同时通过了创建实例的条件判断,然后各自创建一个实例,导致多个实例存在。
  2. 未加同步控制:在最简单的懒汉式实现中,getInstance() 方法没有加上同步控制,这意味着多个线程可以同时进入该方法,从而同时创建多个实例。例如:
public class LazySingleton {
    private static LazySingleton instance;

    private LazySingleton() {
        // 私有构造函数,防止其他类直接实例化
    }

    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton(); // 多个线程可能同时执行到这里,创建多个实例
        }
        return instance;
    }
}

解决方案:

为了解决懒汉式的线程安全问题,可以在 getInstance() 方法上加上同步关键字 synchronized确保在同一时刻只能有一个线程进入该方法,从而避免了多线程并发创建多个实例的情况。例如:

public class LazySingleton {
    private static LazySingleton instance;

    private LazySingleton() {
        // 私有构造函数,防止其他类直接实例化
    }

    public static synchronized LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

3.代码块和初始化顺序

对象初始化顺序:

父类静态代码块->子类静态代码块->父类初始化代码块->父类构造函数->子类初始化代码块->子类构造函数

Parent类:

package com.example.java.day6.Initialize;/**
 * @User HASEE
 * @Author WeiXu
 * @Createtime 2023/7/24-24-14:11
 * @PACKAGE_NAME com.example.java.day6
 */

/**
 *@ClassName:Parent
 *@author weixu
 *@date 2023/7/24 14:11
 */
public class Parent {
    int age = 10;//初始化
    //初始化代码块
    {
        System.out.println("父类的初始化代码块1");
    }
    {
        System.out.println("父类的初始化代码块2");
    }
    //静态初始化代码块
    static
    {
        System.out.println("父类的静态初始化代码块1");
    }
    static
    {
        System.out.println("父类的静态初始化代码块2");
    }
    //构造函数初始化
    public Parent()
    {
        System.out.println("父类的构造函数初始化");
    }

}

Children类:

package com.example.java.day6.Initialize;/**
 * @User HASEE
 * @Author WeiXu
 * @Createtime 2023/7/24-24-14:11
 * @PACKAGE_NAME com.example.java.day6
 */

/**
 *@ClassName:Children
 *@author weixu
 *@date 2023/7/24 14:11
 */
public class Children extends Parent{
     int age = 20;
     //初始化代码块
    {
        System.out.println("子类的初始化代码块1");
    }
    {
        System.out.println("子类的初始化代码块2");
    }
    static
    {
        System.out.println("子类的静态初始化代码块1");
    }
    static
    {
        System.out.println("子类的静态初始化代码块2");
    }

    public Children()
    {
        System.out.println("子类的构造函数初始化");
    }
}

InitializeTest类:

package com.example.java.day6.Initialize;/**
 * @User HASEE
 * @Author WeiXu
 * @Createtime 2023/7/24-24-14:10
 * @PACKAGE_NAME com.example.java.day6
 */

/**
 *@ClassName:InitializeTest
 *@author weixu
 *@date 2023/7/24 14:10
 */
//代码初始化 以及初始化顺序 父类静态代码块->子类静态代码块->父类初始化代码块->父类构造函数->子类初始化代码块->子类构造函数
public class InitializeTest {
    public static void main(String[] args) {
        Children children = new Children();
    }
}

4.final修饰词

  • 修饰类,表示类不能被继承
  • 修饰方法:表示不能被重写
  • 修饰成员变量,表示变量不能被改变
//public  final class ATest //final修饰的类无法被继承
public class ATest {
    final int age = 10;//final修饰的变量,只能赋值一次 无法再改变
//    final void test()
//    {
//        System.out.println("A");
//    }
     void test()
    {
        System.out.println("A");
    }
}
class BTest extends ATest
{
   //无法重写父类被final修饰的方法


    @Override
    void test() {
        System.out.println("B");
    }

    void f1()
    {
        super.test();//final修饰的方法无法被重写,但是可以被调用
        this.test();
        //super.age = 10;//final修饰的变量,只能赋值一次 无法再改变
    }
}

5.抽象类

  • 用abstract关键字来修饰一个类, 这个类叫做抽象类
  • 用abstract来修饰一个方法, 该方法叫做抽象方法。抽象方法:只有方法的声明,没有方法的实现。以分号结束:比如: public abstract void talk();
  • 含有抽象方法的类必须被声明为抽象类。
  • 抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。

ATest类(抽象类):

package com.example.java.day6.abstract_test;/**
 * @User HASEE
 * @Author WeiXu
 * @Createtime 2023/7/24-24-15:26
 * @PACKAGE_NAME com.example.java.day6.abstract_test
 */

/**
 *@ClassName:ATest
 *@author weixu
 *@date 2023/7/24 15:26
 */
public abstract class ATest {
    //抽象类中没有方法体的方法就是抽象方法
    public abstract void test();

    //与接口不同的是抽象类中可以有非抽象方法
    public void f1()
    {
        System.out.println("A");
    }
}

BTest类(ATest类的子类):

package com.example.java.day6.abstract_test;/**
 * @User HASEE
 * @Author WeiXu
 * @Createtime 2023/7/24-24-15:26
 * @PACKAGE_NAME com.example.java.day6.abstract_test
 */

/**
 *@ClassName:BTest
 *@author weixu
 *@date 2023/7/24 15:26
 */
public class BTest extends ATest {

    //void BTest默认为public abstract void BTest();
     void BTest()
    {
        System.out.println("B");
    }

    //父类为抽象类,子类必须重写父类的抽象方法
    @Override
    public void test() {
        System.out.println("B");
    }
}

Test类(测试类):

package com.example.java.day6.abstract_test;/**
 * @User HASEE
 * @Author WeiXu
 * @Createtime 2023/7/24-24-15:43
 * @PACKAGE_NAME com.example.java.day6.abstract_test
 */

/**
 *@ClassName:Test
 *@author weixu
 *@date 2023/7/24 15:43
 */
public class Test {
    public static void main(String[] args) {
        //new ATest(); //抽象类不能直接实例化
        new BTest();
    }
}

6.接口

概念:

  • 一方面, 有时必须从几个类中派生出一个子类, 继承它们所有的属性和方法。 但是, 由于Java不支持多重继承。 有了接口, 就可以得到多重继承的效果
  • 另一方面, 有时必须从几个类中抽取出一些共同的行为特征,而它们之间又没有is-a的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、 MP3机、手机、数码相机、移动硬盘等都支持USB连接
  • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要…则必须能…”的思想。 继承是一个"是不是"的关系,而接口实现则是 "能不能"的关系。
  • 接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。

Usb接口:

//接口中的方法都是抽象方法 不能有方法体
public interface Usb {
    void start();
    void stop();
}

Typc接口:

public interface Typc {
    void transfer();
}

Phone类(接口实现类):

//1.实现类可以实现多个接口 2.实现类需要实现接口中的所有方法
public class Phone implements Usb,Typc{
    public static void main(String[] args) {
        System.out.println("手机");

    }

    @Override
    public void transfer() {
        System.out.println("手机可以传输数据");
    }

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

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

小节:接口和抽象的区别

  • 抽象类可以有非抽象方法接口只能有抽象方法
  • 接口中方法默认public abstract
  • 接口可以实现多继承,抽象类不可以

7. 内部类和匿名内部类

7.1 内部类

java中可以把一个java类放到另一java类的内部,这个类成为内部类

内部类的分类:

  • 成员变量位置,成员内部类
    • static成员内部类
    • 非静态的成员内部类
  • 方法中,局部内部类

语法:

  • 修饰成员变量的所有的修饰符都可以修饰成员内部类
  • 内部类可以使用继承

案例:

Person类:

package com.example.java.day6.inner_class_test;/**
 * @User HASEE
 * @Author WeiXu
 * @Createtime 2023/7/24-24-16:38
 * @PACKAGE_NAME com.example.java.day6.inner_class_test
 */

/**
 *@ClassName:Person
 *@author weixu
 *@date 2023/7/24 16:38
 */
public class Person {
   private String name = "张三";
   private int age = 20;

   //1.静态内部类
   //内部类,如果一个类只给当前外部类使用,别的组件不用,比如Dog和Cat类只是在Person中使用
   //所有的成员变量的修饰符,都可以修饰内部类
    public static class Dog
   {
      public void eat()
      {
          System.out.println("狗吃骨头");
      }
   }
   //2.内部类
    public class Cat
   {
         public void eat()
         {
              System.out.println("猫吃鱼");
         }
   }
   //3.成员方法内部类
    public void f1()
    {
        class Bird
        {
            public void eat()
            {
                System.out.println("鸟吃虫子");
            }
        }
    }

}

7.2 匿名内部类

  • 一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
  • 匿名内部类的特点
    • 匿名内部类必须继承父类或实现接口
    • 匿名内部类只能有一个对象
    • 匿名内部类对象只能使用多态形式引用
  • 语法new 接口(类){实现};

案例:

Usb接口:

package com.example.java.day6.inner_class_test;

/**
 * @User HASEE
 * @Author WeiXu
 * @Createtime 2023/7/24-24-15:22
 * @PACKAGE_NAME com.example.java.day6.interface_test
 */
//接口中的方法都是抽象方法 不能有方法体
public interface Usb {
    //接口方法默认是public abstract
    void start();
    void stop();
}


Typc接口:

package com.example.java.day6.inner_class_test;

/**
 * @User HASEE
 * @Author WeiXu
 * @Createtime 2023/7/24-24-15:22
 * @PACKAGE_NAME com.example.java.day6.interface_test
 */
public interface Typc {
    //接口方法默认是public abstract
    void transfer();
}


Test1类:

package com.example.java.day6.inner_class_test;/**
 * @User HASEE
 * @Author WeiXu
 * @Createtime 2023/7/24-24-16:35
 * @PACKAGE_NAME com.example.java.day6.inner_class_test
 */

/**
 *@ClassName:Test1
 *@author weixu
 *@date 2023/7/24 16:35
 */
public class Test1
{
    public static void main(String[] args) {
         //创建静态成员内部类的方法
        Person.Dog dog = new Person.Dog();//静态内部类的创建方式 静态的是属于类本身的而不是对象的
        dog.eat();
        //创建非静态成员内部类的方法
        Person person = new Person();
        Person.Cat cat = person.new Cat();//非静态内部类的创建方式 非静态的是属于对象的而不是类本身的 因此需要先创建对象 再创建内部类
        cat.eat();

        /**
         * 1:多态性:编译类型是父类
         * 2:new 接口(类),后面跟一个实现
         * 3:有一个对象usb1,实现了Usb接口的一个没有名字的类的实例
         * Test$1->实现了Usb接口->用这个类产生一个对象usb1
         */
        //方式1:匿名内部类 格式:Usb usb1 = new Usb()[...] 
        Usb usb1 = new Usb() {
            @Override
            public void start() {
                System.out.println("手机启动了");
            }

            @Override
            public void stop() {
                System.out.println("手机关机了");
            }
        };
        f1(usb1);

        //方式2:匿名内部类直接作为参数 格式f2(new 接口[...])
          f2(new Typc() {
              @Override
              public void transfer() {
                  System.out.println("TypeC接口的传输功能");
              }
          });
    }

    public static void f1(Usb usb) {
        usb.start();
        usb.stop();
    }

    public static void f2(Typc typeC) {
        typeC.transfer();
    }


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值