Java面向对象(三)

 一、static关键字的使用

  1、static:静态的

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

  3、使用static修饰属性:静态变量(类变量)。

    3.1、属性按是否使用static修饰,又分为:静态属性和非静态属性(实例变量)。

       实例变量:当我们创建了类的多个对象,每个对象都独立的拥有一套类中的静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中的同一属性发生改变。

       静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。通过某一个类修改静态变量之后,通过其他对象调用此变量,变量的值是前一对象修改过后的值。

    3.2、static修饰属性的其他说明

       3.2.1、静态变量随着类的加载而加载。可以通过“类.静态变量”的方式进行调用。

       3.2.2、静态变量的加载要早于对象的创建。

       3.2.3、由于类只加载一次,则静态变量在内存中也只会存在一份,存在方法区的静态域中。

    3.3、          静态属性          非静态属性

        类           ✔              ✖

        对象        ✔              ✔

    3.4、类变量和实例变量内存分析

              

  4、静态方法:使用static修饰的方法称为静态方法

    4.1、随着类的加载而加载,可以通过“类.静态方法”的方式进行调用。

    4.2、          静态方法          非静态方法

        类           ✔              ✖

        对象        ✔              ✔

    4.3、静态方法中只能调用静态的方法或属性。

       非静态方法中既可以调用非静态的方法和属性,也可以调用静态的方法和属性。

  5、static注意点

    5.1、在静态方法内不能用this关键字和super关键字

    5.2、关于静态属性和静态方法的使用,可以从生命周期的角度去理解。

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

    >如果属性是可以被多个对象所共享的,不会随着对象的不同而不同,则可定义为静态属性。

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

    >操作静态属性的方法通常定义为静态方法。

    >工具类中的方法通常定义为静态方法。

public class StaticTest {
    public static void main(String[] args) {
        Chinese.nation = "中国";

        Chinese c1 = new Chinese();
        c1.name = "姚明";
        c1.age = 40;
        c1.nation = "china";

        Chinese c2 = new Chinese();
        c2.name = "马龙";
        c2.age = 30;
        System.out.println(c1.nation);// 输出结果:china
        c2.nation = "CHINA";
        System.out.println(c1.nation);// 输出结果:CHINA

        //对象可以调用静态方法
        c2.show();
    }
}

class Chinese {
    String name;
    int age;
    static String nation;

    public void eat() {
        System.out.println("中国人吃中餐");
    }

    public static void show() {
        System.out.println("我爱我的祖国");
        // 不能调用非静态结构
//        eat();  //Cannot make a static reference to the non-static method eat() from the type Chinese
        // 可以调用静态结构
        System.out.println(Chinese.nation);
        walk();
    }

    public void info() {
        System.out.println("name :" + name + ",age :" + age);
    }

    public static void walk() {
        System.out.println("删库跑路");
    }
}

 二、单例设计模式

  1、单例设计模式,就是采用一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例。

  2、实现方式:

    2.1、“饿汉式”

public class SingletonTest1 {
    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、内部创建类的对象
    // 要求此对象必须声明为静态的
    private static Bank instance = new Bank();

    // 3、提供获取实例的方法
    public static Bank getInstance() {
        return instance;
    }
}

    2.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、声明当前类的对象
    private static Order instance = null;
    //3、声明静态返回实例的方法。
    public static synchronized Order getInstance() {
        if (instance == null) {
            instance = new Order(); 
        }
        return instance;
    }
}

  3、区分饿汉式和懒汉式

    饿汉式:

      坏处:对象加载时间长

      好处:线程安全

    懒汉式:

      好处:延迟对象的加载,节省内存空间

  4、应用场景:网站计数器、应用程序的日志系统、数据库连接池、读取配置文件、

三、类的成员之四:代码块(初始化块)

  1、代码块的作用:用于初始化类、对象。

  2、代码块如果有修饰符的话,只能使用static。

  3、分类:静态代码块、非静态代码块

  4、静态代码块:

    4.1、内部可以有输出语句。

    4.2、随着类的加载而执行。

    4.3、作用:初始化类的信息。

    4.4、如果一个类中定义了多个静态代码块,则按其声明的先后顺序执行。

    4.5、静态代码块的执行,要先于非静态代码块。

    4.6、静态代码块内只能调用静态的属性、静态的方法、不能调用非静态结构。

  5、非静态代码块:

    5.1、内部可以有输出语句。

    5.2、随着对象的创建而执行。

    5.3、每创建一个对象执行一次。

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

    5.5、如果一个类中定义了多个非静态发代码块,在对象创建时按其声明的先后顺序执行。

    5.6、非静态代码块内可以调用静态属性,静态方法,非静态属性,非静态方法。

public class BlockTest {
    public static void main(String[] args) {
        String desc = Persion.desc;
        Persion p1 = new Persion();
    }
}

class Persion {
    // 属性
    String name;
    int age;
    static String desc = "我是人类";

    // 构造器
    public Persion() {

    }

    public Persion(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 非静态代码块
    {
        System.out.println("block-2");
    }
    {
        System.out.println("block-1");
    }

    // 静态代码块
    static {
        System.out.println("static block-2");
    }
    static {
        System.out.println("static block-1");
    }

    // 方法
    public void eat() {
        System.out.println("吃饭");
    }

    @Override
    public String toString() {
        return "Persion  [name = " + name + ",age = " + age + "]";
    }

    public static void info() {
        System.out.println("我是一个快乐的人!");
    }
}

四、属性赋值的先后顺序

  1、默认初始化(数据类型默认值)。

  2、显式初始化 / 在代码块中赋值。(按先后顺序)

  3、构造器中初始化。

  4、有了对象之后,通过“对象.属性”或“对象.方法”的方式,进行赋值。

五、final关键字

  1、final可以修饰的结构:类、方法、变量。

  2、final修饰的类不能被其他类继承。

  3、final修饰的方法不能被重写。

  4、final修饰的变量为常量。(常量名称通常用大写字母表示)

    4.1、final修饰属性:可以赋值的位置有:显式初始化、代码块中初始化、构造器中初始化。

    4.2、final修饰局部变量:

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

  5、static final 用来修饰属性:全局常量。

 六、抽象类与抽象方法(abstract关键字使用)

  1、abstract:抽象的。

  2、abstract可以用来修饰的结构:类、方法。

  3、abstract修饰类:抽象类

    3.1、abstract修饰的类不能实例化。

    3.2、抽象类中一定有构造器,便于子类对象实例化时调用。

    3.3、开发中,都会提供抽象类的子类,让子类对象实例化,完成相关操作。

  4、abstract修饰方法:抽象方法。

    4.1、抽象方法只有方法的声明,没有方法体。例:public abstract void setXxx();

    4.2、包含抽象方法 的类一定是抽象类。但抽象类中可能没有抽象方法。

    4.3、若子类重写了父类中的所有的抽象方法后,方可实例化。

       若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要用abstract修饰。 

  5、abstract使用时注意点:

    5.1、abstract不能修饰属性,构造器等结构。

    5.2、abstract不能修饰私有方法、静态方法、final修饰的方法、final修饰的类。

public class AbstractTest {

}

abstract class Persion {
    String name;
    int age;

    public Persion() {

    }

    public Persion(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /*
     * public void eat() { System.out.println("人吃饭"); }
     */

    public void walk() {
        System.out.println("人走路");
    }

    public abstract void eat();
    public abstract void breath();
}

class Student extends Persion {
    public Student(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void breath() {
        // TODO Auto-generated method stub
        
    }

}

七、抽象类的匿名子类

public class PersionTest {

    public static void main(String[] args) {
        method(new Student());

        Worker w1 = new Worker();
        method1(w1);// 非匿名类 非匿名对象
        method1(new Worker());// 非匿名类 匿名对象
        Persion p = new Persion() {// 创建了匿名子类对象P

            @Override
            public void eat() {
                // TODO Auto-generated method stub

            }

            @Override
            public void breath() {
                // TODO Auto-generated method stub

            }
        };

        // 创建匿名子类的匿名对象
        method1(new Persion() {

            @Override
            public void eat() {
                // TODO Auto-generated method stub

            }

            @Override
            public void breath() {
                // TODO Auto-generated method stub

            }

        });
    }

    public static void method(Student s) {

    }

    public static void method1(Persion p) {
        p.eat();
        p.breath();
    }
}

class Worker extends Persion {

    @Override
    public void eat() {
        // TODO Auto-generated method stub

    }

    @Override
    public void breath() {
        // TODO Auto-generated method stub

    }

}

八、接口:interface

  1、 接口用interface来定义。

  2、Java中接口和类是并列的两个结构。

  3、如何定义接口:

    3.1、JDK7及以前:只能定义全局常量和抽象方法。

      3.1.1、全局常量:只能定义public static final的,可以省略不写。

      3.1.2、抽象方法:只能定义为public abstract的,可以省略不写。

    3.2、JDK8:除了定义全局变量和抽象方法外,还可以定义静态方法、默认方法(default修饰)。

      3.2.1、接口中定义的静态方法,只能通过接口来调用。

      3.2.2、通过实现类的对象可以调用接口中的默认方法。

          如果实现类重写了接口中的默认方法,调用时,调用的是重写以后的方法。

      3.2.3、如果子类(或实现类)继承的父类和实现的借口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。------>类优先原则。

      3.2.4、如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么实现类在没有重写此方法的情况下报错。------>接口冲突。这就需要我们必须在实现类中重写此方法。

      3.2.5、在实现类中调用接口中被重写的方法:  接口名.super.method();

      3.2.6、默认方法可以通过实现类对象来调用。

  4、接口中不能定义构造器,即接口不能被实例化。

  5、Java开发中,接口通过让类去实现(implements)的方式来使用。

    如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化。

    如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类。

  6、Java类可以实现多个接口,弥补了 Java单继承的局限性。

    格式:class AA extends BB implements CC , DD{}

  7、接口与接口间可以继承,而且可以多继承。

九、类的成员之五:内部类

  1、Java中允许将一个类A声明在类B中,则类A就是内部类,类B称为外部类。

  2、内部类的分类:成员内部类、局部内部类(方法内,代码块内,构造器内)。

  3、成员内部类:

    3.1、作为外部类成员:

      3.1.1、调用外部类的结构。例:“Persion.this.eat();”。

      3.1.2、可被static修饰。

      3.1.3、可以被4种不同权限修饰。

    3.2、作为一个类:

      3.2.1、类内可以定义属性、方法、构造器等。

      3.2.2、可被final修饰,表示此类不能被继承;不使用final就可以被继承。

      3.2.3、可以被abstract修饰。

  4、使用

    4.1、如何实例化成员内部类的对象。

    4.2、如何在成员内部类中区分调用外部类的结构。

    4.3、开发中局部内部类的使用。

  5、注意点

    在外部类方法中的局部内部类的方法,调用该内部类所在方法的局部变量时,要求此局部变量声明为final的。

      JDK7及以前的版本该局部变量必须显式声明为final的。

      JDK8及以后的版本可以省略final的声明。

public class InnerClassTest {
    public static void main(String[] args) {
        //创建Dog实例(静态成员内部类)。
        Person.Dog dog = new Person.Dog();
        //创建Bird实例(非静态成员内部类)。
        /*
         * No enclosing instance of type Persion is accessible. Must qualify the
         * allocation with an enclosing instance of type Persion (e.g. x.new A() where x
         * is an instance of Persion). 
         * Persion.Bird bird = new Persion.Bird();
         */
        Person p = new Person();
        Person.Bird bird = p.new Bird();
        bird.sing();
        
        System.out.println(""
                + ""
                + ""
                + ""
                + "");
        
        
        
        bird.test("鹦鹉");
        
    }
    
    //开发中局部内部类使用
    
    //一般不用此方法
    public void method() {
        //局部内部类
        class AA {
            
        }
    }
    
    //常见使用方式
    //例:返回一个实现了Comparable接口的类的对象
    //方式一
//    public Comparable getComparable() {
//        //创建实现Comparable接口的类
//        class MyComparable implements Comparable{
//
//            @Override
//            public int compareTo(Object o) {
//                // TODO Auto-generated method stub
//                return 0;
//            }
//            
//        }
//        return new MyComparable();
//        
//    }
    //方式二
    public Comparable getComparable() {
        return new Comparable() {

            @Override
            public int compareTo(Object o) {
                // TODO Auto-generated method stub
                return 0;
            }
            
        };
    }

}
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("汪汪汪·····");
        }
    }
    //非静态成员内部类
    class Bird{
        String name = "凤凰";
        public Bird() {
            
        }
        
        public void sing(){
            System.out.println("一只鸟");
            Person.this.eat();//调用外部类非静态的属性。
        }
        
        
        //在成员内部类中调用外部类的结构
        public void test(String name) {
            System.out.println(name);//方法形参
            System.out.println(Person.this.name);//外部类属性
            System.out.println(this.name);//内部类属性
            System.out.println(new Person.Dog().name);//调用并列静态内部类
        }
        
    }
    
    public void method() {
        //局部内部类
        class AA {
            
        }
    }
    {
        //局部内部类
        class BB{
            
        }
    }
    public Person(){
        //局部内部类
        class CC{
            
        }
    }
}

 

posted @ 2021-03-25 23:18  早春的树  阅读(62)  评论(0)    收藏  举报