Java的几个高级类特性

1.static关键字

(1)static属性

例如要写一个中国人的类,那么不必为每个对象都分配一个中国国籍对象。而是所有人共用一个。
设置时通过类设置,访问时也通过类访问。如下:

class Chinese {
    public static String country;
}

public class Test {
    public static void main(String[] args) {
        Chinese.country = "中国";
        System.out.println(Chinese.country);
    }
}

实例变量:
只有实例化之后才能使用,属于实例化对象的一部分,不能共用。

类变量:
使用类名调用,是类的一部分,被这个类的所有实例化对象所共享。也可以叫做静态变量

如下代码中,country属于类变量,而name属于实例变量。

class Chinese {
    public static String country;
    public String name;
}

所以如果想让一个类的所有实例共享数据,则需使用类变量。

(2)static方法

如果方法与调用者无关,则这样的方法通常被声明为类方法。由于不需要创建对象就可以调用方法,从而简化了方法的调用过程。
也称为静态方法
静态方法常应用于工具类。如下是一个判断字符串不为空的工具类。

class Tool {
    public static boolean isEmpty(String s) {
        boolean flag = false;
        if (s != null && !s.equals(""))
            flag = true;
        return flag;
    }
}
(3)static关键字总结

使用范围
在Java类中,可用static修饰属性、方法、代码块、内部类。

被修饰后的成员具备以下特点:

  • 随着类的加载而加载。
  • 优先于对象存在。
  • 被所有对象共享。(可用于计数)
  • 访问权限允许时,可不创建对象,直接被类调用。

如下,可用静态方法来计数new了多少个对象。

class CountObject {
    static int count;
    public CountObject() {
        CountObject.count += 1;
    }
    public static void show() {
        System.out.println(CountObject.count);
    }
}

注意:

  • 使用类变量时要慎重。
  • static方法内部不能有this和super。
  • 重载的方法需要同时为static的或者非static的。
(4)单例(Singleton)设计模式

所谓单例设计模式,就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。

应用场景:
实例化对象的创建要消耗大量的时间和资源。或频繁new对象没有意义。

单例设计模式之一:饿汉式

分为以下三个步骤:

  1. 构造方法私有化。无法再通过new来创建该类的对象。
  2. 创建一个该类型的私有类变量。
  3. 通过一个public静态方法访问这个私有类变量。

如下:

class Example {
    private Example() {}  //重写构造方法
    private static Example e = new Example();  //创建唯一实例作为私有类变量
    public static Example getInstance() {
        return e;
    }  //为类外访问该唯一实例提供public方法
}
单例设计模式之二:懒汉式

它与饿汉模式的区别是,它一开始没有new对象(null),直到第一次调用才new出一个对象,而之后所有调用都是调用这个唯一的对象。
所以,这两种单例模式的根本区别在于,对象何时创建

懒汉式的步骤为:

  1. 构造方法私有化。
  2. 创建该类型的一个私有变量,但赋值为null。
  3. 创建一个public静态方法访问这个私有变量。如果当前为null,则new一个;如果当前不是null,则直接返回已有的私有变量。

如下:

class Example {
    private Example() {}
    private static Example e = null;
    public static Example getInstance() {
        if (e == null) {
            e = new Example();
        }
        return e;
    }
}

懒汉式存在线程安全问题,待续。

2.main方法的语法

public static void main(String[] args) {}
  • JVM需要调用类的main方法,所以该方法必须是public。
  • 执行main方法时不需要创建对象,它是一个类方法,所以为static。
  • main方法接受一个String类型的数组参数,该数组中保存执行Java命令时传递给所运行的类的参数。

如下:

public class TestMain {
    public static void main(String[] args) {
        for (int i = 0; i < args.length; i++)
            System.out.println(args[i]);
    }
}

编译后,若执行如下命令:

java TestMain.java aa bb cc

则打印输出:

aa
bb
cc

3.类的成员之四:初始化块(代码块)

作用:
对Java对象进行初始化。
如下:

public class Test {
    String name;
    public Test() {
        System.out.println("构造方法");
    }
    {
        System.out.println("代码块");
    }

    public static void main(String[] args) {
        Test t = new Test();
    }
}

则输出为:

代码块
构造方法

执行顺序为:

  1. 类的属性的默认初始化和显示初始化。
  2. 执行代码块的代码。
  3. 执行构造器的代码。

如果有多个代码块,则顺序执行:

public class Test {
    {
        System.out.println("代码块1");
    }
    {
        System.out.println("代码块2");
    }
    {
        System.out.println("代码块3");
    }

    public static void main(String[] args) {
        Test t = new Test();
    }
}

输出为:

代码块1
代码块2
代码块3
静态代码块

被static修饰的代码块称为静态代码块。代码块只有static一个修饰符。
静态代码块中只能对静态属性和静态方法进行初始化。
无论new多少个对象,静态代码块只执行一次。如下:

public class Test {
    static int i;
    static void showInfo() {
        System.out.println("静态方法");
    }
    static
    {
        i = 1;
        showInfo();
        System.out.println("执行静态代码块");
    }

    public static void main(String[] args) {
        Test t1 = new Test();
        Test t2 = new Test();
    }
}

执行结果为:

静态方法
执行静态代码块

静态代码块一般用于初始化类的静态属性。

对比
非静态代码块:没有static修饰的代码块
  • 可以有输出语句。
  • 可以对类的属性进行初始化操作。
  • 可以调用静态或非静态的变量或方法。
  • 若有多个非静态的代码块,按照从上到下的顺序依次执行。
  • 每次创建对象的时候,都会执行一次。
  • 优先于构造器执行。
静态代码块:用static修饰的代码块
  • 不可以对非静态的属性初始化,即不可以调用非静态的属性和方法。
  • 若有多个静态代码块,则按顺序执行。
  • 静态代码块优先于非静态代码块执行。
  • 静态代码块只执行一次。

在实际开发中,static静态代码块用来初始化类的静态属性。

在匿名内部类中,用代码块代替构造方法。

class Animal {
     String name;
    void Animal() {
        this.name = "xiaohua";
    }
    void printInfo() {
        System.out.println("Animal");
    }
}

public class Test {
    public static void main(String[] args) {
        Animal a = new Animal() {
            {
                super.name = "xiaoming";
            }

            @Override
            void printInfo() {
                System.out.println("Test");
            }
        };
        System.out.println(a.name);
        a.printInfo();
    }
}

则输出为:

xiaoming
Test

4.final关键字

使用final修饰类、属性和方法,表示“最终”。

  • final修饰的类不能被继承。例如String类、System类、StringBuffer类。
  • final修饰的方法不能被子类重写。例如Object类中的getClass()。
  • final修饰的变量(成员变量或局部变量)则为常量,注意一般将其名称大写,如有多个单词则用下划线连接。常量必须显式赋值且只能赋值一次。
  • final static一起修饰的变量就叫做全局常量。

5.抽象类

有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。

abstract关键字:

  • 用abstract修饰的类叫做抽象类。
  • 用abstract修饰的方法叫做抽象方法。抽象方法只包含方法的声明,不包含方法的实现,以分号结束。abstract int abstractMethod(int a);
  • 含有抽象方法的类必须被声明为抽象类。
  • 抽象类不能被实例化。抽象类是用来作为父类被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,则仍为抽象类。
  • 不能用abstract修饰属性、私有方法、构造器、静态方法、final的方法。

抽象类应用
抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。

抽象类不能实例化,new AbstractClass()是非法的。

模板方法设计模式(TemplateMethod)

抽象类体现的是一种模板模式的设计。抽象类作为多个子类的通用模板,子类在抽象类的基础上进行改造、扩展,但子类总体上会保留抽象类的行为方式。

abstract class Template {
    public abstract void code();
    public final void getTime() {
        long start = System.currentTimeMillis();
        code();
        long end = System.currentTimeMillis();
        System.out.println("执行时间为:" + (end - start));
    }
}

class Code1 extends Template{
    public void code() {
        int k = 1;
        for (int i = 0; i <1000000; i++)
        {
            k += 1;
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Code1 c = new Code1();
        c.getTime();
    }
}

当功能内部一部分实现是确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。

6.接口(interface)

  • 有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是Java不支持多重继承。利用接口可以实现多重继承的效果。
  • 接口是抽象方法和常量值的定义的集合。
  • 从本质上讲,接口是一种特殊的抽象类,这种抽象类只包含常量方法的定义,而没有变量和方法的实现。
  • 接口类的实现:class SubClass implements intergaceA{}
  • 一个类可以实现多个接口,接口也可以继承其他接口。

接口的特点:

  • 用interface来定义;
  • 接口中的所有成员变量都默认是由public static final修饰的,即全局静态常量;
  • 接口中的所有方法都默认是由public abstract修饰的;
  • 接口没有构造器,不能new;
  • 接口采用多层继承机制;
  • 实现接口的类必须提供接口中所有方法的具体实现内容(大括号),方可实例化。否则仍为抽象类,要在类前加abstract才不会报错;
  • 接口的主要用途就是被实现类实现;
  • 与继承关系类似,接口与实现类之间存在多态性;
  • 语法格式:险些extends,后写implements。

一般来讲,抽象类是对一类事物的高度抽象,其中既有属性也有方法。
接口是对方法的抽象,也就是对一系列动作的抽象。

工厂方法(FactoryMethod)

FactoryMethod模式是设计模式中应用最广泛的模式。

在面向对象的编程中,对象的创建工作非常简单,对象的创建时机却很重要。FactoryMethod通过面向对象的手法,将所要创建的具体对象的创建工作延迟到了子类,从而提供了一种扩展的策略,较好地解决了这种紧耦合的关系。

7.类的成员之5:内部类

  • 若一个类位于另一个类的内部,则前者为内部类,后者为外部类。
  • Inner class 可以使用外部类的私有数据。若外部类要访问内部类中的成员需要以如下形式:内部类.成员 或 内部类对象.成员。
public class External {
    private int id;

    class A{
        public void setExternal() {
            id = 1;
        }
    }
    public void setInfo() {
        new A().setExternal();
    }
    public void showInfo() {
        System.out.println(this.id);
    }
}

内部类的特点:

  • 可以是final的;
  • 可以是private和protected的;
  • 可以为static的,但此时不能再使用外部类的非 static 成员变量;
  • 可以声明为abstract的,因此可以被其他的内部类继承;
  • 非static的内部类中的成员不能声明为static的,只有在外部类或static的内部类中才可声明static成员。

内部类主要是解决Java不能多重继承的问题。
可以使用内部类来变相实现类的多重继承,可以同时继承多个类。
比如说想在A类中同时重写B的一个方法和C的一个方法。则:
public class Test {
public static void main(String[] args) {
A a = new A();
a.testB();
a.testC();
}
}

class A {
    public void testB() {
        new InnerB().testB();
    }
    public void testC() {
        new InnerC().testC();
    }

    private class InnerB extends B {
        @Override
        public void testB() {
            System.out.println("重写B中的方法");
        }
    }
    private class InnerC extends C {
        @Override
        public void testC() {
            System.out.println("重写C中的方法");
        }
    }
}
class B {
    public void testB() {

    }
}
class C {
    public void testC() {

    }
}

输出为:

重写B中的方法
重写C中的方法

所以,内部类的最大作用是实现多重继承

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值