Java【第八篇】面向对象之高级类特性

static 关键字

当咱们编写一个类时,其实就是在描述其对象的属性和行为,而并无产生实质上的对象,只有经过new关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才能够供外部调用。咱们有时候但愿不管是否产生了对象或不管产生了多少对象的状况下,某些特定的数据在内存空间里只有一份,例如全部的中国人都有个国家名称,每个中国人都共享这个国家名称,没必要在每个中国人的实例对象中都单独分配一个用于表明国家名称的变量。在Java类中声明变量、方法和内部类时,可以使用关键字static作为修饰符。static标记的变量或方法由整个类(全部实例)共享,如访问控制权限容许,可没必要建立该类对象而直接用类名加‘.’调用。static成员也称类成员或静态成员,如:类变量、类方法、静态方法等。java

类变量

类变量(类属性)由该类的全部实例共享,类属性相似于全局变量。编程

类方法

没有对象的实例时,能够用类名.方法名()的形式访问由static标记的类方法;
在static方法内部只能访问类的static属性,不能访问类的非static属性。
由于不须要实例就能够访问static方法,所以static方法内部不能有this,(也不能有super ) 设计模式

在静态方法里只能直接调用同类中其它的静态成员(包括变量和方法),而不能直接访问类中的非静态成员。这是由于,对于非静态的方法和变量,须要先建立类的实例对象后才可以使用,而静态方法在使用前不用建立任何对象。
静态方法不能以任何方式引用this和super关键字。与上面的道理同样,由于静态方法在使用前不用建立任何实例对象,当静态方法被调用时,this所引用的对象根本就没有产生。
main() 方法是静态的,所以JVM在执行main方法时不建立main方法所在的类的实例对象,于是在main()方法中,咱们不能直接访问该类中的非静态成员,必须建立该类的一个实例对象后,才能经过这个对象去访问类中的非静态成员,这种状况,咱们在之后的例子中会屡次碰到。数组

类属性、类方法的设计思想

类属性做为该类各个对象之间共享的变量。在设计类时,分析哪些类属性不因对象的不一样而改变,将这些属性设置为类属性。相应的方法设置为类方法。
若是方法与调用者无关,则这样的方法一般被声明为类方法,因为不须要建立对象就能够调用类方法,从而简化了方法的调用安全

示例

练习1:编写一个类,实现银行帐户的概念,包含的属性有“账号”、“密码”、“存款余额”、“利率”、“最小余额”,定义封装这些
属性的方法。帐号要自动生成。
编写主类,使用银行帐户类,输入、输出3个储户的上述信息。
考虑:哪些属性能够设计成static属性。 Bank.java ide

package com.uncleyong;

/**
 * 编写一个类,实现银行帐户的概念,包含的属性有“账号”、“密码”、“存款余额”、“利率”、“最小余额”,定义封装这些
 * 属性的方法。帐号要自动生成。
 */
public class BankAccount {
    //初始化的 id
    private static int initId = 1000;

    //帐号
    private String id;

    //密码
    private String password;

    //余额
    private int balance;

    //利率
    private static double rate;

    //最小余额
    private static int minBalance;

    public BankAccount(String password, int balance) {
        this.id = "" + (initId++);  // initId自增
        this.password = password;
        this.balance = balance;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getBalance() {
        return balance;
    }

    public void setBalance(int balance) {
        this.balance = balance;
    }

    public static double getRate() {  // 对象有static修饰符,因此对应的get方法也会自动加static
        return rate;
    }

    public static void setRate(double rate) {
        BankAccount.rate = rate;
    }

    public static int getMinBalance() {  // 对象有static修饰符,因此对应的get方法也会自动加static
        return minBalance;
    }

    public static void setMinBalance(int minBalance) {
        BankAccount.minBalance = minBalance;
    }

    @Override
    public String toString() {
        return "BankAccount{" +
                "id='" + id + "'" +
                ", password='" + password + "\'" +
                ", balance=" + balance +
                ", rate=" + rate +
                ", minBalance=" + minBalance +
                '}';
    }
}

  

package com.uncleyong;

/**
 * 编写主类,使用银行帐户类,输入、输出3个储户的上述信息。
 */
public class TestBank {

    public static void main(String[] args) {

        //统一设置 rate 和 minBalance
        BankAccount.setMinBalance(100);
        BankAccount.setRate(0.01);

        BankAccount acc1 = new BankAccount("1234", 100);
        BankAccount acc2 = new BankAccount("1235", 200);
        BankAccount acc3 = new BankAccount("1236", 300);

        System.out.println(acc1);
        System.out.println(acc2);
        System.out.println(acc3);
    }

}

静态初始化

一个类中可使用不包含在任何方法体中的静态代码块(static block ),当类被载入时,静态代码块被执行,且只被执行一次,静态块常常用来进行类属性的初始化。
static块一般用于初始化static (类)属性函数

class Person {
    public static int total;
    static {
        total = 100;//为total赋初值 
    }
    …… //其它属性或方法声明
} 

单子 Singleton 设计

设计模式是在大量的实践中总结和理论化以后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就想是经典的棋谱,不一样的棋局,咱们用不一样的棋谱,省得咱们本身再去思考和摸索。
所谓类的单态设计模式,就是采起必定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,而且该类只提供一个取得其对象实例的方法。若是咱们要让类在一个虚拟机中只能产生一个对象,咱们首先必须将类的构造方法的访问权限设置为private,这样,就不能用new 操做符在类的外部产生类的对象了,但在类内部仍能够产生该类的对象。由于在类的外部开始还没法获得类的对象,只能调用该类的某个静态方法以返回类内部建立的对象,静态方法只能访问类中的静态成员变量,因此,指向类内部产生的该类对象的变量也必须定义成静态的。测试

class Single{
 	private static Single onlyone = new Single();//私有的,只能在类的内部访问
 	private String name;
	public static Single getSingle() {   //getSingle()为static,不用建立对象  
                                //便可访问
 		return onlyone;
 	}
 	private Single() {}     //private的构造器,不能在类的外部建立该类的对象
  	}

public class TestSingle{
	public static void main(String args[]) {		
	Single  s1 = Single.getSingle();      //访问静态方法
	Single  s2 = Single.getSingle();
	if (s1==s2){
			    System.out.println("s1 is equals to s2!");
		         }
	}
}

理解main方法的语法

因为java虚拟机须要调用类的main()方法,因此该方法的访问权限必须是public,又由于java虚拟机在执行main()方法时没必要建立对象,因此该方法必须是static的,该方法接收一个String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数。this

package com.uncleyong;

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

结果spa

final 关键字 

在Java中声明类、属性和方法时,可以使用关键字final来修饰。
final标记的变量(成员变量或局部变量)即成为常量,只能赋值一次。final PI=3.14;
final标记的类不能被继承。提升安全性,提升程序的可读性。
final标记的方法不能被子类重写。增长安全性。
final标记的成员变量必须在声明的同时或在每一个构造方法中显式赋值,而后才能使用。

示例

package com.uncleyong;

public class TestFinal {

    int i = 10;
    int j;

    final int m = 10;
    final int n;

    public TestFinal() {  // 构造方法中赋值
        n = 100;
    }

    public void test(){  // 能够在方法中为成员变量赋值
        i = 10;
        j = 20;

//		m = 100;
    }

    public static void main(String[] args) {
        TestFinal testFinal = new TestFinal();
        System.out.println(testFinal.i + " "+ testFinal.j);  // 10 0
        testFinal.test();
        System.out.println(testFinal.i + " "+ testFinal.j);  // 10 20

    }

}

final class A{

}

//class B extends A{
//
//}

class C{
    void method1(){}
}

class D extends C{
    @Override
    void method1() {
        super.method1();
    }
}

抽象类(abstract 关键字) 

随着继承层次中一个个新子类的定义,类变得愈来愈具体,而父类则更通常,更通用。类的设计应该保证父类和子类可以共享特征。有时将一个父类设计得很是抽象,以致于它没有具体的实例,这样的类叫作抽象类。
用abstract关键字来修饰一个类时,这个类叫作抽象类;用abstract来修饰一个方法时,该方法叫作抽象方法。抽象方法只有方法的声明,没有方法的实现,以分号结束。abstract int abstractMethod1( int a );
含有抽象方法的类必须被声明为抽象类。抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。不能用abstract修饰私有方法,构造方法,静态方法。

抽象类是用来模型化那些父类没法肯定所有实现,而是由其子类提供具体实现的对象的类。  

示例

package com.uncleyong;

public class TestAbstract {

    public static void main(String[] args) {
        E e = new F();
    }

}

abstract class E{
    abstract void test();  // 抽象方法没有方法体

    private void aa(){}
}

class F extends E{

    @Override
    void test() {

    }

    void aa(){}

}

abstract class G extends E{

}  

接口(interface 关键字) 

有时必须从几个类中派生出一个子类,继承它们全部的属性和方法。可是,Java不支持多重继承。有了接口,就能够获得多重继承的效果。
接口(interface)是抽象方法和常量值的定义的集合。
从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。接口定义举例

public interface Runner {
    int id = 1;
    public void start();
    public void run();
    public void stop();
}

接口的特色:

用 interface 来定义。
接口中的全部成员变量都默认是由public static final修饰的。
接口中的全部方法都默认是由public abstract修饰的。接口没有构造方法。
实现接口的类中必须提供接口中全部方法的具体实现内容。
多个无关的类能够实现同一个接口
一个类能够实现多个无关的接口
与继承关系相似,接口与实现类之间存在多态性
接口也能够继承另外一个接口,使用extends关键字。

定义Java类的语法格式:

< modifier> class < name> [extends < superclass>][implements < interface> [,< interface>]* ] {
    < declarations>*
}

示例

定义一个接口用来实现两个对象的比较。

interface CompareObject{
    public int compareTo(Object o); 
    //若返回值是 0 , 表明相等; 若为正数,表明当前对象大;负数表明当前对象小
}

定义一个Circle类。
定义一个ComparableCircle类,继承Circle类而且实现CompareObject接口。在ComparableCircle类中给出接口中方法compareTo的实现体,用来比较两个圆的半径大小。
定义一个测试类TestInterface,建立两个ComaparableCircle对象,调用compareTo方法比较两个类的半径大小。
思考:参照上述作法定义矩形类Rectangle和ComparableRectangle类,在ComparableRectangle类中给出compareTo方法的实现,比较两个矩形的面积大小。 

package com.uncleyong;

interface CompareObject{
    //若返回值是 0 , 表明相等; 若为正数,表明当前对象大;负数表明当前对象小
    public int compareTo(Object o);  // 当前对象和对象o比较
}

  

package com.uncleyong;


public class Circle {

    protected double radius;

    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
    }

    public Circle(double radius) {
        this.radius = radius;
    }

}

  

package com.uncleyong;

/**
 * 定义一个ComparableCircle类,继承Circle类而且实现CompareObject接口。
 * 在ComparableCircle类中给出接口中方法compareTo的实现体,用来比较两个圆的半径大小。
 */
public class ComparableCircle extends Circle implements CompareObject{

    public ComparableCircle(double radius) {
        super(radius);  // 父类只有一个有参构造函数
    }

    @Override
    public int compareTo(Object o) {  // 当前对象和对象o比较

        //1. 检验 o 是否为 Circle 类型
        if(o instanceof Circle){
            Circle circle = (Circle) o;  // 强转
            //2. 比较半径
            return (int)(this.radius - circle.radius);
        }

        return 0;
    }

}

  

package com.uncleyong;

public class TestInterface {
    public static void main(String[] args) {
        ComparableCircle cc1 = new ComparableCircle(2);
        ComparableCircle cc2 = new ComparableCircle(7);

        ComparableCircle cc3 = new ComparableCircle(2);
        ComparableCircle cc4 = new ComparableCircle(1);

        ComparableCircle cc5 = new ComparableCircle(2);
        ComparableCircle cc6 = new ComparableCircle(2);

        System.out.println(cc1.compareTo(cc2));
        System.out.println(cc3.compareTo(cc4));
        System.out.println(cc5.compareTo(cc6));
    }
}

内部类及匿名内部类

在Java中,容许一个类的定义位于另外一个类的内部,前者称为内部类
内部类和外层封装它的类之间存在逻辑上的所属关系
Inner class通常用在定义它的类或语句块以内,在外部引用它时必须给出完整的名称。 Inner class的名字不能与包含它的类名相同;
Inner class可使用包含它的类的静态和实例成员变量,也可使用它所在方法的局部变量;

Inner class能够声明为抽象类 ,所以能够被其它的内部类继承。也能够声明为final的。
和外层类不一样,Inner class能够声明为private或protected;
Inner class 能够声明为static的,但此时就不能再使用外层封装类的非static的成员变量;
非static的内部类中的成员不能声明为static的,只有在顶层类或static的内部类中才可声明static成员。

示例

package com.uncleyong;

public class OuterClass {

    int age;

    // 静态内部类,不能够引用外部类非静态成员,由于有静态内部类的时候,可能还没外部类的对象
    static class StaticInnerClass{
        void test(){
//            System.out.println(age);  // 报错
        }
    }

    String name = "-1";  // 写为static String name = "-1";,也能够被非静态内部类引用

    // 非静态内部类,能够引用外部类的非静态和静态成员
    class InnerClass{
        String name = "0";
        public void test(){
            String name = "1";

            System.out.println(name); //1
            System.out.println(this.name); //0
            System.out.println(OuterClass.this.name); //-1
        }

    }
}

  

package com.uncleyong;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

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

        OuterClass.StaticInnerClass sic = new OuterClass.StaticInnerClass();  // 静态内部类的建立: 再也不须要外部类的实例

        OuterClass oc = new OuterClass();  // 非静态内部类的建立, 先建立外部类的实例, 再经过 外部类名.new 建立内部类的实例
        OuterClass.InnerClass in = oc.new InnerClass();
        in.test();

        // InvocationHandler是一个接口,直接建立接口new InvocationHandler(),同时提供其方法的实现
        // 实际上是建立了一个内部类对象,可是不知道其名字(有对象名,没内部类名),因此叫匿名内部类对象
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
        };

        // 写得更确切一点(纯匿名内部类对象,连对象的引用都没有;建立一个接口的对象,直接提供其方法的实现)
        Proxy.newProxyInstance(null, null, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
        });
    }
}
相关文章
相关标签/搜索