文章目录
1.4 访问控制 public protected friendly private
类的访问权限:public friendly
成员方法:public protected friendly private
成员变量:public protected friendly private
与A1在同一个包下:
class A2 {
public static void main(String[] args) {
A1 a = new A1();
a1.f1(); // public
a1.f2(); // protected
a1.f3(); // friendly
System.out.println(a.a1); // public
System.out.println(a.a2); // protected
System.out.println(a.a3); // friendly
}
}
与A1在不同包下:
class A {
public static void main(String[] args) {
A1 a = new A1();
a1.f1(); // public
super.f2(); // protected
System.out.println(a.a1); // public
System.out.println(super.a2); // protected
}
}
1.5 代码复用
1.组合
将类的对象置于某个新的类中,“创建一个成员对象”。
- 被视为has-a(拥有)关系。
- 新类的成员变量通常被声明为private,使得新类的客户端程序员不能访问他们。
- 处处使用继承,会导致设计过于复杂,在建立新类时应该首先考虑组合。
2.继承
源类(基类、超类、父类)副本(导出类、继承类、子类)
- 如果只是简单地继承一个类而并不做其他任何事情,那么基类中的接口方法将会直接继承到导出类中。这意味着导出类的对象不仅与基类拥有相同的类型,还拥有相同的行为,这样做没有什么特别意义。
有两种方法可以使基类与导出类产生差异
- 直接在导出类中添加新方法。
- 改变现有基类的方法,覆盖。使用相同的接口方法,但是做不同的事情。
只改变基类方法时,导出类is a 基类。添加新方法后,导出类is like a基类。
1.7 多态
在处理类型的层次结构时,经常会把一个对象不当作它所属的特定类型来对待,而是将其当做其基类的对象来对待。这使得人们可以编写出不依赖于特定类型的代码。
void doSomething(Animal animal) {
Animal.eat(); // 将导出类看做是它的基类的过程称为向上转型
Animal.run(); // 通过父类引用调用非导出类特有方法时,最终会调用子类的方法
Animal.read(); // 报错,父类引用不能直接调用子类的特有方法
Human human = (Human) animal; // 只能通过将父类引用强制转换为子类,即向下转型
human.read();
}
Animal a = new Human();
doSomething(a);
1.8 单根继承结构
所有的类都继承自单一的基类,Object。
1.9 容器
容器:创建一种对象类型,持有对其他对象的引用。
- Java类库中具有满足不同需要的各种类型的容器,如List(存储序列),Map(关联数组,建立对象之间的关联),Set(每种对象类型只持有一种)。
- 不同容器提供了不同类型的接口和外部行为。不同的容器对于某些操作具有不同的效率。如对于随机访问元素,ArrayList比较快。对于在序列中插入一个元素,LinkedList比较快。
参数化类型
- 在java SE5之前,容器存储的对象都只具有Object类型,所以可以存储Object的容器可以存储任何东西。
- 但是由于容器只存储Object,所以当对象引用置入容器时,它必须向上转型为Object。当把它取回时,就获取了一个对Object对象的引用。除非将对象强制转换,否则无法调用导出类的特有方法,而向下转型必须记住这些对象是什么类型,同时还需要额外的时间。
- 为了容器在创建时保存对象的类型,从而不需要向下转型,提出了参数化类型机制,编译器可以定制一个只接纳和取出指定类型的容器。
- 参数化类型在Java中叫做泛型,一对尖括号,中间包含类型信息。
ArrayList<Shape> shapes = new ArrayList<Shape>();
1.10 对象的创建和生命期
在使用对象时,最关键的问题之一便是它们的生成和销毁方式。每个对象为了生存都需要资源,尤其是内存。当我们不再需要一个对象时,它必须被清理掉,使其占有的资源可以被释放和重用。
- C++为了追求最大的执行速度,必须在编写程序时确定对象确切的数量、生命周期和类型,将对象置于堆栈、静态存储区域。这种方式认为效率控制是最重要的议题,将存储空间分配和释放置于优先考虑的位置,但牺牲了灵活性。
- Java完全采用了动态内存分配方式(在被称为堆的内存池中动态地创建对象,直到运行时才知道需要多少对象、生命周期、具体类型)。每当想要创建新对象时,就要使用new关键字来构建此对象的动态实例。Java只能在堆上创建对象。
- 对于允许在堆栈上创建对象的语言,编译器可以确定对象存活的时间,并可以自动销毁它。然而如果是在堆上创建对象,编译器就会对它的生命周期一无所知。对于C++必须通过编程方式确定何时销毁。Java提供了垃圾回收。
1.11 异常处理
Java内置了异常处理,而且强制你必须使用它。如果没有编写正确的处理异常的代码,那么就会得到一条编译时的出错消息。
1.12 并发编程
把问题切分成多个可独立运行的部分,从而提高程序的响应能力。在程序中,这种彼此独立运行的部分称之为线程,上述概念被称为并发。
并发的隐患:共享资源。如果有多个并行的任务都要访问同一项资源,那么就会出问题。因此,某个任务应当锁定某项资源,完成其任务,然后释放资源锁,使其他任务可以使用这项资源。