Java面向对象编程-第7章学习笔记

来源:互联网 发布:家 医疗软件 编辑:程序博客网 时间:2024/05/16 10:14

第7章 Java语言中的修饰符

一、访问控制修饰符
(1)public:公开级别,对同类、同包、子类和不同的包都公开;
(2)protected:保护级别,对同类、同包、子类公开;
(3)默认级别:对同类、同包公开;
(4)private:私有级别,只对同类公开。

//*包A:public class Ca{  public int v1;  protected int v2;  int v3;  private int v4;}class Cb{  ...}//*包B:class Cc extends Ca{  public int v1;  protected int v2;  int v3;  private int v4;}class Cd{  ...}

对于上述代码
Ca当然可以访问其自身的所有成员,包括v1\v2\v3\v4;
Cb可以访问Ca的v1\v2\v3;
Cc可以访问Ca的v1\v2;
Cb可以访问Ca的v1。

二、abstract修饰符
abstract可以用来修饰类和成员方法。
(1)用abstract修饰的类称为抽象类,抽象类无法实例化。但是:用abstract修饰的类中可以没有抽象方法,但包含了抽象方法的类必须被修饰为抽象类。如果子类没有实现父类的所有抽象方法,则子类也必须被定义为抽象类。
(2)用abstract修饰的方法表示抽象方法,抽象方法没有方法体。一般用来描述系统具有的功能,但不提供具体实现。对于构造方法和静态成员方法而言,不能用abstract修饰。
(3)抽象类中可以有构造方法,创建子类实例时可能会调用这个构造方法。
(4)抽象类不能被实例化,但可以定义一个抽象类类型的引用变量,引用其非抽象子类的实例对象。
(5)抽象类和方法都不能用final修饰。abstract和final修饰符不可以同时使用。(*为什么这么设计?设想一下,如果可以同时使用,那么对于这个类来说,因为用final修饰了,所以其不能有子类;而其又是abstract类,必须通过子类去实现。那这里final和abstract同时修饰的类是毫无意义的,因为无法实现,无法实例化。)
(6)抽象类不能被实例化的深入:
a、从逻辑上,抽象类用来表示一些从具体类中抽象出来的类型,比如生活里的水果类,其子类包括苹果类、桔子类。如果:

Fruit fruit=new Fruit();   //现实是没有水果这个东西的Fruit fruit=new Apple();  //但可以有苹果这个具体的水果

b、从语法上,抽象类可能包括抽象方法,如果实现了抽象类的实例对象,那这个实例对象无法实现这个抽象方法。

三、final修饰符
final具有“不可改变”的含义,可以修饰非抽象类、非抽象成员方法和变量。
(1)用final修饰的类不能被继承,没有子类。
(2)用final修饰的方法不能被重写。
(3)用final修饰的变量表示常量,只能被赋一次值。
(4)final不能修饰构造方法。因为方法重写这个概念只适用于类的成员方法,而不适用于构造方法,用final修饰构造方法是毫无意义的。父类中private修饰的方法是不能被子类的方法覆盖的,所以private类型的方法默认是final类型的。
1、final类
Java中的继承关系容易打破封装,可以通过final修饰类进行类的保护:
(1)明确不会继承的类。
(2)出于安全的原因,类的实现细节不允许被改动。
比如JDK中java.lang.String类被定义为final类型:

public final class String{..}

2、final方法
某些情况下,父类不允许子类重写其某个方法,这种情况就可以把这个方法声明为final类型,如java.lang.Object类中,getClass()方法为final类型,而equals()不是final类型。
3、final变量
final修饰的变量表示取值不会改变的常量,具有以下特征:
(1)final可以修饰静态变量、实例变量和局部变量,分别代表静态常量、实例常量和局部常量。例如某个学校招生,每个学生都有姓名年龄,其中假设姓名永远不会改变,则用实例常量描述,年龄每年都会变化,用一般实例变量描述。该学校只招收年龄在10-18岁的学生。那对于这个限制年龄,因为对于每个学生都是一致的,并且不会变化的,因此考虑用静态常量去描述。

package tsjava;public class Student{      public static final int MAX_AGE=18;  //静态常量      public static final int MIN_AGE=10;  //静态常量      private final String name;   //私有实例常量      private int age;      public Student(String name,int age){        this.name=name;        if(age>MAX_AGE||age<MIN_AGE)           System.out.println("不符合入学年龄条件!");        this.age=age;      }      public void setAge(int age){          this.age=age;      }      static{          System.out.println("招生开始----------");      }      public static void main(String[] args){          Student s1=new Student("GTS",15);          Student s2=new Student("ShuJing",19);          Student s3=new Student("QQ",10);          s1.setAge(17);          System.out.println("学生1:"+s1.name+"  "+s1.age+"岁");          System.out.println("学生1:"+s2.name+"  "+s2.age+"岁");          System.out.println("学生1:"+s3.name+"  "+s3.age+"岁");      }    }

(2)对于final修饰的变量:静态常量必须在声明时赋值;实例常量必须在声明时赋值,或者在构造方法中初始化。
(3)final变量只能赋一次值。对于下个示例:

public class Sample{  static final int MAX_LENGTH=10;   //静态常量  final int vmax;          //实例常量  Sample(){          //通过构造函数给实例常量赋值,合法    vmax=1;  }  Sample(int x){     //通过构造函数给实例常量赋值,合法    vmax=x;  }  /*虽然上述出现了两次给实例常量vmax赋值   *但创建对象时,只会执行一个构造方法   *所以上面代码是合法的   */

(4)如果将引用类型的变量用final修饰,那么该变量只能引用一个对象,但可以改变对象的内容,示例:

public class Sample{  public int var;  public Sample(int var){this.var=var;}  public static void main(String[] args){    final Sample samp=new Sample();      samp.var=2;         //合法,可以更改对象内容    samp=new Sample();  //编译出错,无法改变samp引用的对象(即指向地址不能变)  }}

四、static修饰符
static可以修饰类的成员变量、成员方法和代码块。静态成员变量和静态成员方法可以通过类名来访问。对于静态代码块,当JVM加载类的时候,就会执行该代码块,并且只在加载时执行一次。
被static修饰的成员变量和方法表示归整个类及其所有实例对象所有。只要这个类被加载,JVM就可以根据类名在运行时数据区的方法区定位找到。
1、static变量
(1)静态变量在整个内存里只有一个拷贝,运行时JVM只为其分配一次内存。
(2)实例变量在创建其对应实例对象时候为该变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响。
示例:有一群选民进行投票,每个人只能投一次票,并且当投票达到100时就停止投票。针对这个例子可以抽象出Voter类,类的成员变量中包括选民的姓名(对应实例变量),累计投票次数每次都会被改变(对应静态变量),投票次数限制数100(对应静态常量)。

package tsjava;import java.util.Set;import java.util.HashSet;import java.util.Iterator;public class Voter {    private static final int MAX_COUNT=100;   //最大投票数    private static int count;       //累计投票数    private String name;    private static Set<Voter> voters=new HashSet<Voter>();   //投票人信息    Voter(String name){        this.name=name;    }    /*投票程序*/    public void voteFor(){        if(count==MAX_COUNT){            System.out.println("投票已经结束!");            return;        }        if(voters.contains(this)){            System.out.println("你不能重复投票!");            return;        }        count++;        voters.add(this);        System.out.println("感谢你的投票!");    }    /*打印投票结果*/    public static void printVoterResult(){        System.out.println("当前投票数为:"+count);        System.out.println("参与投票的选民如下:");        for(Voter v:voters){            System.out.println(v.name);        }    }    static{        System.out.println("-------------------------");        System.out.println("-----------开始投票---------");        System.out.println("-------------------------");    }    public static void main(String[] args){        Voter tom=new Voter("Tom");        Voter mike=new Voter("Mike");        Voter jack=new Voter("Jack");        tom.voteFor();        mike.voteFor();        tom.voteFor();        jack.voteFor();        Voter.printVoterResult();    }}

2、static方法
(1)静态方法可访问的内容
因为静态方法不需要通过它所属的类的实例对象就可以调用,因此静态方法中不能使用this关键字,也不能直接访问所属类的实例变量和实例方法,但可以直接访问所属类的静态变量和静态方法。一般来说,需要创建一个针对整个类的方法则需要使用静态方法,如上例中的printVoteResult方法。
(2)实例方法可访问的内容。实例方法可以直接访问所属类的所有成员,不必显式地添加类名。
(3)静态方法必须被实现,即static和abstract不能同时使用。
(4)作为程序入口的main()方法是静态方法,具备前述静态方法的特点。将main()定义为static则在JVM加载其所属类的时候就可以执行main()方法,而无须先创建实例。
(5)方法的字节码都位于方法区:不管实例方法还是静态方法,在Java编译器把Java源程序编译成字节码后,存储在方法区。
3、static代码块
JVM加载类的时候会执行这些静态代码块,如果一个类包括多个静态代码块,则按其在代码中出现的次序依次执行。每个静态代码块只在类加载时候执行一次。静态代码块与静态方法一样,不能直接访问类的实例变量和实例方法,必须通过实例的引用去访问。

0 0
原创粉丝点击