Java编程思想 访问权限控制

访问权限控制

1.Java文件组织

.java文件: 一个包中有多个.java文件,每个java文件都是一个编译单元。编译一个.java文件时,.java文件中的每个类都会有一个输出文件,输出文件名称和.java文件中每个类的名称相同,只是多一个后缀名.class。每个编译单元内只能有一个public类,该类的名称必须与文件的名称相同(包括大小写)。非public类对包外不可见,主要为public class服务。

可运行程序:是一组可以打包并压缩为一个Java文档文件的.class文件。

package: 类库是一组类文件,每个文件都有一个public类,以及任意数量的非public类。因此每个文件都有一个构件。若将这些构件(每一个都有自己独立的.java和.class文件)从属于同一个群组,就可以使用关键字package。除注释外的第一行代码,在文件起始处写。

注意Java包的命名全部选用小写字母。

2.类库的使用

使用import关键字:import java.lang.* import java.util.ArrayList

条件编译:不改变程序代码,可以切换开关产生不同的行为,如调试功能。

3.包权限访问修饰词

pubic、protected、friendly、private

包访问权限:
  • 如果包中成员为public,则包及包之外都可以访问该成员。
  • 如果包中成员为friendly,则只有包之内的才能对其进行访问。
  • 如果包中成员为private,则只有包含该成员的类才能对其进行访问。——但是可以通过访问器(accessor)和变异器(mutator)方法(get/set)读取或者改变原来的值。
  • 继承的类可以访问protected和public成员
//get、set方法
public class User{
    private String username;
    private int age;
    public void setUsername(String username){
        this.username = username;
    }
    public char getUsername(String username){
        return username;
    }
}

类的访问权限修饰符:public friendly

成员变量和成员方法访问权限修饰符:private public protected friendly

4.重点程序 lunch.java:
class Soup1{
    private Soup1() {}//构造器私有化
    public static Soup1 makesoup(){//用static方法不创建对象,调用构造器
        return new Soup1();
    }
}
class Soup2{
    private Soup2() {}
    private static Soup2 ps1 = new Soup2();
    //私有的静态对象,容易忘记ps1是静态的
    public static Soup2 access(){
        return ps1;//只能访问唯一的Soup2对象
    }
    public void f() {}
}
public class Lunch{
    void testStatic() {
        Soup1 soup = Soup1.makesoup();//静态方法创建对象,可创建多个
    }
    void testSingleton() {
        Soup2.acess().f();//只可以访问唯一的一个对象
    }
}
5.包名的编码和解析

包名的第一部分是类的创建者的反顺序的域名。

第二部分是将package名称分解为机器上的一个目录。当Java程序运行需要加载class文件时,可以确定文件在目录上所处的位置。首先,Java解释器将找出环境变量CLASSPATH,CLASSPATH包含一个或多个目录,用作查找.class文件的根目录。从根目录开始,解释器获取包的名称并将每个句点替换成反斜杠,以从CLASSPATH根中产生一个路径名称。

6.封装

封装:封装是指把数据成员和相关方法都放进一个类中,并使用访问权限来控制其可见性。

第六章 复用类

1.组合

在新类中使用现有类的对象作为成员变量。由于新的类是有现有类的对象组成,所以这种方法称为组合。

组合复用的是功能

对象引用的三种初始化方法:

  • 指定初始化:

定义对象的地方进行初始化,这意味着在构造器调用之前他们完成了初始化。

  • 构造器初始化:

构造器中初始化对象。

  • 懒惰初始化

就在正要使用对象之前,进行初始化。对象引用初始化为NULL。

2.继承

按照现有类的类型创造新类。不改变类的形式,增加新的成员变量和方法。

继承复用的是接口。

为便于继承,成员变量定义为private,方法定义为public。

2.1 extends 和 super 关键字用法:
class Cleanser{
    public void scrub() {}
}
public class Detergent extends Cleanser{//用extends
    public void scrub(){
        append("Detergent.scrub()");
        super.scrub();//调用基类的方法
    }
}

super用于调用基类的方法,和在基类构造器带参数的情况下,在派生类构造器中显式调用基类构造器

class Game{
    Game(int i) {
    }
}
class BoardGame extends Game{
    BoardGame(int i){
        super(i);
    }
}
//或者也可以
class ComputerGame extends Game{
    Computer(){
        super(11);
    }
}
2.2 名称屏蔽

如果Java中基类已经拥有某个已被多次重载的方法名称,那么在导出类中重新定义该方法并不会屏蔽在基类中的任何版本(这一点与C++不同)。

重写是重新覆盖父类的方法,在一些子类要实现的方法中,方法名、参数列表和返回值类型都和父类的方法一样,但具体实现与父类不同,这时候就需要重写父类的方法。

如果没有重写,那么子类调用一个子类没有的方法时,实际上是在调用父类。

以下是方法重载的一个例子。

class Homer {
    char doh(char 'c') {
        print("doh(char)");
    }
    float doh(float f) {
        print("doh(float)");
    }
}
class Milhouse {}
class Bart extends Homer {
    void doh(Milhouse m) {
        print("doh(Milhouse)");
    }
}
public class Hide{
    public static void main(String[] args) {
        Bart b = new Bart();
        b.doh(1);//doh(float)
        b.doh('x');//doh(char)
        b.doh(new Milhouse());//doh(Milhouse)
    } //不能构造b.doh(0.2324);可以构造b.doh(0.2324f);
}
2.3 基类中的protected成员和方法可以被派生类访问
3.final关键字
3.1 final数据

对于基本类型,final使基本类型的数值不发生改变。

对于对象引用,final使引用恒定不变。但是对象的数值是可以修改的。

必须在域的定义处或者每个构造器中用表达式对final进行赋值。

注意:是每个构造器!

final与static:

对于常量,两者差别不大。最好使用public static final来声明常量。

带有恒定初始值的final static常量全部用大写字母命名,单词之间用下划线隔开。

private final int valueone = 9;
private static final int VAULE_TWO = 99;

对于特殊变量:也不能认为某数据是final的,所以一定可以在编译前知道它的值。

private final int i4 = rand.nextInt(20);
//每次new新对象时值会改变,对于同一个对象值不变
private static final int INT_5 = rand.nextInt(20);
//对于所有创建的对象,经过第一次创建对象初始化后,值永远不会发生改变。
final参数:

Java允许在参数列表中,以声明的方式将参数指明为final。这意味着将无法在方法中更改引用所指向的对象。

3.2 final方法

目的:锁定方法,防止派生类修改;考虑效率,如果一个方法是final的,所有对该方法的调用都转为内嵌调用。

3.3 final类

不可以被继承

4.基类的初始化

(1)在创建派生类对象时,该对象包含一个基类的子对象。基类的子对象的初始化是通过调用基类构造器实现,自动在派生类的构造器中插入对基类构造器的调用。

(2)基类的构造器在派生类构造器之前被调用。

(3)如果没有默认的构造器或构造器带参数必须显式的调用。

class Insect {
  int i = 9;
  int j;
  int m = prt("Insect.m initialized");
  Insect() {
    prt("i = " + i + ", j = " + j);
    j = 39;
  }
  static int x1 = 
    prt("static Insect.x1 initialized");
  static int prt(String s) {
    System.out.println(s);
    return 47;
  }
}

public class Beetle extends Insect {
  int k = prt("Beetle.k initialized");
  int l = prt("Beetle.l initialized");
  Beetle() {
    prt("k = " + k);
    prt("j = " + j);
  }
  static int x2 =
    prt("static Beetle.x2 initialized");
  public static void main(String[] args) {
    prt("Beetle constructor");
    Beetle b = new Beetle();
  }
} 

第一步:访问Beetle.main()函数

第二步:加载器启动并找出Beetle类的编译代码(在Beetle.class中)

第三步:继续加载基类Insect.class

第四步:对基类中的static进行初始化

第五步:对派生类中的static进行初始化

第六步:创建对象

第七步:将对象的内存设为二进制零值,所有的基本类型设为默认值,所有的引用设为NULL

第八步:基类实例变量初始化

第九步:调用基类构造器

第十步:派生类实例变量初始化

十一步:调用派生类构造器

执行结果:

static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
Insect.m initialized
i = 9, j = 0
Beetle.k initialized
Beetle.l initialized
k = 47
j = 39

猜你喜欢

转载自blog.csdn.net/LJFYYJ/article/details/80976905
今日推荐