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

第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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值