JAVA编程基础——类和对象(继承、多态)

一、单利模式

(1)单例类只能有一个实例;

(2)单例类必须自己创建自己的唯一实例;

(3)单例类必须给所有其他对象提供这个实例。

场景:一个类可以定义无数个对象,但是只有一个实例。

1、饿汉式单利模式

package practise.test1030;
//饿汉式单利模式
class MySingleTon2{
    private static MySingleTon2 singleTon = new MySingleTon2();
    private MySingleTon2(){
        System.out.println("MySingleTon2().init");
    }

    //提供一个全局的访问点
    public static MySingleTon2 getInstance(){
        return singleTon;
    }
}

public class Test2 {
    public static void main(String[] args) {
        MySingleTon2 mySingleTon = MySingleTon2.getInstance();
        MySingleTon2 mySingleTon2 = MySingleTon2.getInstance();
        MySingleTon2 mySingleTon3 = MySingleTon2.getInstance();
        MySingleTon2 mySingleTon4 = MySingleTon2.getInstance();
        System.out.println(mySingleTon);
        System.out.println(mySingleTon2);
        System.out.println(mySingleTon3);
        System.out.println(mySingleTon4);//地址相同
    }
}

2、懒汉式单利模式

package practise.test1030;
//懒汉式单利模式
class MySingleTon{
    private static Object lock = new Object();
    private static MySingleTon singleTon = null;

    private MySingleTon(){
        System.out.println("MySingleTon().init");
    }

    //提供一个全局的访问点
    //可重入函数:线程安全的函数     静态条件    临界区代码段      原子性操作   加锁

    public static MySingleTon getInstance(){
        //1
        /**
         * 原子操作
         * 多进程时,第一个进程还未来得及new一个对象,singleTon==null
         */
        if(singleTon == null){
            singleTon = new MySingleTon();
        }

        //2
        //单线程浪费空间
        synchronized (lock){
            if(singleTon == null){
                singleTon = new MySingleTon();
            }
        }

        //3
        //多线程时至少执行两次
        if(singleTon == null){
            synchronized (lock){
                singleTon = new MySingleTon();
            }
        }

        //4     双重检验    (double-checked locking)
        if(singleTon == null){
            synchronized (lock){
                if(singleTon == null){
                    singleTon = new MySingleTon();
                }
            }
        }

        return singleTon;
    }
}
public class Test1 {
    public static void main(String[] args) {
        MySingleTon mySingleTon = MySingleTon.getInstance();
        MySingleTon mySingleTon2 = MySingleTon.getInstance();
        MySingleTon mySingleTon3 = MySingleTon.getInstance();
        MySingleTon mySingleTon4 = MySingleTon.getInstance();
        System.out.println(mySingleTon);
        System.out.println(mySingleTon2);
        System.out.println(mySingleTon3);
        System.out.println(mySingleTon4);//地址相同
    }
}

3、静态内部类实现单利模式

package practise.test1030;
//静态内部类实现单利模式
//只有访问静态内部类的时候,才会创建对象
class MySingleTon3{
    private MySingleTon3(){

    }

    private static class SingleTon{
        private static MySingleTon3 single = new MySingleTon3();
    }

    public static MySingleTon3 getInstance(){
        return SingleTon.single;
    }
}
public class Test3 {
    public static void main(String[] args) {
        MySingleTon3 single = MySingleTon3.getInstance();
        MySingleTon3 single2 = MySingleTon3.getInstance();
        MySingleTon3 single3 = MySingleTon3.getInstance();
        MySingleTon3 single4 = MySingleTon3.getInstance();
        System.out.println(single);
        System.out.println(single2);
        System.out.println(single3);
        System.out.println(single4);
    }
}

二、继承

继承是一种机制,可以进行代码的重用。在JAVA中,所有的继承都是公有继承。子类比超类拥有的功能更加丰富

基类(超类):

子类(派生类):

在通过扩展类定义子类的时候,仅需要指出子类与超类的不同之处。所以在设计类的时候应该将通用的方法放在超类,而将具有特殊用途的方法放在子类当中。

在子类中可以增加域、增加方法或覆盖超类的方法,但是绝对不能删除继承的任何域和方法。

注:

关键字this有两个用途:1、引用隐式参数;2、调用该类其他的构造器。

super关键字也有两个用途:1、调用超类的方法;2、调用超类的构造器。

在调用构造器的时候,这两个关键字的使用方式很相似:调用构造器的语句只能作为另一个构造器的第一条语句出现。构造参数既可以传递给本类(this)的其他构造器,也可以传递给超类(super)的构造器。

package practise.test1030;
//继承
/**
 * super关键字:
 * super();——调用基类的构造函数
 * super.data——访问基类的数据成员
 * super.func()——调用基类的成员方法
 */

/**
 * 基类
 */
class Base{
    public int ma;

    public Base (int ma){
        this.ma = ma;
    }

    //Base的静态代码块
    static {
        System.out.println("Base.static{}");
    }

    //Base的实例代码块
    {
        System.out.println("Base.instance");
    }

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

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

/**
 * 派生类
 * 继承父类除构造函数外的所有属性
 * 派生类构造对象的初始化顺序
 * 基类静态
 * 派生类静态
 * 基类实例
 * 基类构造方法
 * 派生类实例
 * 派生类构造方法
 */

class Derieve extends Base {
    private int mb;

    public Derieve(int a,int b){
        super(a);//必须放在第一行
        this.ma = ma;
    }

    //Base的静态代码块
    static {
        System.out.println("Base.static{}");
    }

    //Base的实例代码块
    {
        System.out.println("Base.instance");
    }

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

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

//ERROR
/**
 * 继承了ma,没有继承构造函数,
 * 如何构造基类的数据成员???(调用基类的构造函数)
 */
/*class Derieve extends Base{
    private  int mb;
}*/

/**
 * ERROR
 * 派生类的构造函数只能构造派生类的数据成员,不能构造基类的数据成员
 *
class Derieve extends Base {
    private int mb;
    public Derieve(int a,int b){
        //ERROR ma = a;
        this.mb = mb;
    }
}*/

public class Test4 {
    public static void main(String[] args) {
        Base base = new Base(100);
        Derieve derieve = new Derieve(111,222);//new对象  1、分配类存  2、
        /**
         * JAVA中只支持向上继承
         */
        base = derieve;
        /**
         * 基类和派生类之间的相互赋值
         */

        /**
         * 重载:overloade:函数名相同,参数列表不同,和返回值没关系
         * 并不一定是在同一个类当中,在继承关系上也能构成重载
         * 重写(覆盖)overwrite;函数名相同,参数列表相同,函数返回值相同
         * 返回值不同能否构成重载:???
         * 遵守协变类型——JAVA编程思想
         */

    }
}

问题一:派生类继承了父类除构造方法外的所有属性。

问题二:super关键字:

super关键字:

(1)super();——调用基类的构造函数

(2)super.data——访问基类的数据成员

(3)super.func()——调用基类的成员方法

问题三:派生类构造对象的初始化顺序?

(1)基类静态;
(2)派生类静态;
(3)基类实例;
(4)基类构造方法;
(5)派生类实例;
(6)派生类构造方法。
package practise.test1030;

//(public)基类的数据成员在派生类中的访问权限

class Base1{
    public int ma;

//    public Base (int ma){
//        this.ma = ma;
//    }

    //Base的静态代码块
    static {
        System.out.println("Base.static{}");
    }

    //Base的实例代码块
    {
        System.out.println("Base.instance");
    }

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

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

//class Derieve1 extends Base {
//
//}

public class Test5 {
    public static void main(String[] args) {

    }
}

问题四:基类数据成员在派生类当中的访问权限:

(public)基类的数据成员在派生类当中的访问权限
  同包子类 同包非子类 不同包子类 不同包非子类
public     可以      可以       可以       可以
private        /         /          /          /
proctected      可以      可以       可以          /

默认权限

(包访问权限)

      可以       可以         /          /

问题五:重载和重写(覆盖):

(1)重载:overloade:函数名相同,参数列表不同,和返回值没关系。

          注:并不一定是在同一个类当中,在继承关系上也能构成重载 。

(2)重写(覆盖)override:函数名相同,参数列表相同,函数返回值相同。

三、多态

多态:基类引用,引用了派生累对象,并且和派生类有同名的覆盖方法。

JAVA实现多态有三个必要条件:继承、重写、向上转型。

(1)继承:在多态中必须存在有继承关系的子类和父类;

(2)重写:子类对父类中的某些方法进行重新定义,在调用这些方法时就会调用子类的方法;

(3)向上转型:在多态中,只有将子类的引用赋给父类对象,才能够调用父类的方法和子类的方法。

问题六:构造函数内,能不能发生多态?

问题七:动多态和静多态的理解:

(1)动多态:发生在运行的时候(重载);

(2)静多态:发生在编译的时候(重写).

在JAVA只有两种方式可以实现多态:继承和实现接口。

猜你喜欢

转载自blog.csdn.net/weixin_42479293/article/details/83582327