Java编程思想学习笔记_3(继承,内部类)
一、继承与清理
如果某个类需要去清理自身的资源,那么必须用心为其创建回收垃圾的方法,而如果此类有导出的子类,那么必须在导出类中覆盖回收的方法,当覆盖被继承类的回收垃圾的方法的时候,需要注意销毁的顺序应该和初始化的顺序相反。对于字段来说,意味着与声明的顺序相反。应该先对导出类进行清理,然后才是基类。这是因为导出类的清理可能会调用基类的某些方法,所以需要使基类的构件仍起作用而不应过早的销毁他们。
如果需要去销毁被多个成员对象共享的变量的时候,这种情况会变得很复杂。这种情况下,可以使用引用计数法来跟综访问着共享对象的代码数量,代码如下:
import static net.mindview.util.Print.*;
class Shared {
private int refcount=0; //标识引用该变量的个数
private static long counter=0;
private final long id=counter++; //标识Shared变量
public Shared() {
print("Creating "+this);
}
public void addRef() {
refcount++;
}
protected void dispose() {
if(--refcount==0) {
print("Disposing "+this);
}
}
public String toString() {
return "Shared"+id;
}
}
class Composing {
private Shared shared;
private static long counter=0;
private final long id=counter++;
public Composing(Shared shared) {
print("Creating "+this);
this.shared=shared;
this.shared.addRef();
}
protected void dispose() {
print("disposing "+this);
shared.dispose();
}
public String toString() {
return "Composing"+id;
}
}
public class ReferenceCounting { public static void main(String[] args) {
Shared shared=new Shared();
Composing[] composing={new Composing(shared),new Composing(shared),
new Composing(shared),new Composing(shared)};
for(Composing c:composing) {
c.dispose();
}
} }
二、构造器内部的多态方法的行为
如果调用构造器内部的一个动态绑定的方法的时候,就需要用到那个方法被覆盖后的定义,动态绑定的方法调用导出类的方法,此时导出类成员变量还未被初始化,可能会产生错误。
public class Test {
public static void main(String[] args) {
new NewSon().print();
}
}
abstract class Father {
String fs="Dad!";
public Father() {
print();
}
public abstract void print();
}
class NewSon extends Father {
int i=4;
String ss="son!";
public void print() {
System.out.println("Son.."+i);
// System.out.println(ss.toUpperCase()); error
}
}
小细节:如果一个类实现了一个接口,同时继承了另外一个类,如果被继承的类有和接口中同样方法签名的方法,那么子类可以不用提供对于方法的实现。父类继承过来的方法相当于在子类中实现了接口。
interface Eat {
public void eat();
}
class Dog {
public void eat() {
}
}
public class BadDog extends Dog implements Eat {}
三、内部类的一些细节
1.如果在内部类生成对外部类的引用,可以通过外部类的名字加上.this,这样产生的引用会自动具有正确的开销.但是.this只能在外部类内部和内部类使用,其他类里不能使用.
2.在匿名内部类中,如果基类需要一个有参数的构造器,也可以传递参数给基类的构造器,代码如下:
class Wrapping {
private int i;
public Wrapping(int x) {
i=x;
}
public int value() {
return i;
}
}
class Parcel8 {
public Wrapping wrapping(int x)/*传入基类构造器*/ {
return new Wrapping(x) {
public int value() {
return 47*super.value();
}
};
}
}
3.接口中也可以声明内部类,接口中的内部类自动被声明为public 和 static的类型,甚至可以在内部类中实现外部接口.
interface Dog {
public void bark();
class GoodDog implements Dog {
@Override
public void bark() {
System.out.println("bark!");
}
}
}
4.在继承内部类的时候,指向外围类的秘密的引用必须也要被初始化,因此使用特殊的语法来明确说明这种关联:
class WithInner {
class Inner{
int i=0;
public Inner (int i) {
this.i=i;
}
}
}
class InheritInner extends WithInner.Inner {
public InheritInner(WithInner withInner, int i) {
withInner.super(i);
}
}
5.当继承外部类的时候。内部类并没有什么变化,两个内部类完全是独立的个体,各自在各自的命名空间内。
四、为什么需要内部类
1.每个内部类都能独立的继承自一个接口的实现,无论外部类继承了什么类对于内部类没有任何影响。而由于内部类也可以使用外部类的成员,因此,内部类有效的实现了“多重继承”。
class GrandFather {
protected int gf=3;
}
class Father extends GrandFather {
protected int ft=2;
class Son extends Father {
protected int s=1;
public void say() {
System.out.println(gf+" "+ft+" "+s);
}
}
}
2.利用内部类实现命令模式。
可以将命令模式中的命令类放入调用者的内部来实现命令模式,代码如下:
public class Test4 {
public static void main(String[] args) {
GreenHouseControl gh=new GreenHouseControl();
gh.new LightOn().execute();
gh.new LightOff().execute();
gh.new WaterOn().execute();
gh.new WaterOff().execute();
}
}
interface Command /*命令接口*/{
public void execute();
}
class GreenHouseControl {
private boolean light=false;
class LightOn implements Command {
@Override
public void execute() {
System.out.println("The light is on.");
light=true;
}
}
class LightOff implements Command {
@Override
public void execute() {
System.out.println("The light is off.");
light=false;
}
}
private boolean water=false;
class WaterOn implements Command {
@Override
public void execute() {
System.out.println("The water is on");
water=true;
}
}
class WaterOff implements Command {
@Override
public void execute() {
System.out.println("The water is off");
water=false;
}
}
}
对于内部类的知识原理性整理可参见:http://www.cnblogs.com/hlhdidi/p/5575607.html http://www.cnblogs.com/hlhdidi/articles/5575416.html
Java编程思想学习笔记_3(继承,内部类)的更多相关文章
- Java编程思想学习笔记_2(继承和多态)
静态初始化: 静态初始化只在必要的时刻进行.(即当程序需要加载类进入内存的时候,执行静态初始化.静态变量和静态代码块的初始化顺序,按照在代码中声明的顺序老执行.例如:如果要执行某个public类,那么 ...
- [Java编程思想-学习笔记]第3章 操作符
3.1 更简单的打印语句 学习编程语言的通许遇到的第一个程序无非打印"Hello, world"了,然而在Java中要写成 System.out.println("He ...
- Java编程思想 学习笔记10
十.内部类 可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类是一种非常有用的特性,因为它允许你把一些逻辑相关的类组织在一起,并控制位于内部的类的可视性.然而必须要了解,内部类和组合是 ...
- 《Java编程思想》笔记 第十章 内部类
1.创建内部类对象 创建内部类对象(相当于new内部类对象) 外围类对象.new 内部类( ). 创建内部类对象一种方法是 外围类有一个方法返回内部类对象. 没有外围类对象就不能创建内部类对象,因为内 ...
- Java编程思想 学习笔记1
一.对象导论 1.抽象过程 Alan Kay曾经总结了第一个成功的面向对象语言.同时也是Java所基于的语言之一的Smalltalk的五个基本特性,这些特性表现了纯粹的面向对象程序设计方式 1)万物皆 ...
- [Java编程思想-学习笔记]第1章 对象导论
1.1 抽象过程 Java是一门面向对象的语言,它的一个优点在于只针对待解问题抽象,而不用为具体的计算机结构而烦心,这使得Java有完美的移植性,也即Java的口号"Write Once, ...
- Java编程思想 学习笔记11
十一.持有对象 通常,程序总是根据运行时才知道的某些条件去创建新对象.在此之前,不会知道所需对象的数量,甚至不知道确切的类型. Java实用库还提供了一套相当完整的容器类来解决这个问题,其中基本的类 ...
- Java编程思想学习笔记——类型信息
前言 运行时类型信息(RTTI:Runtime Type Information)使得我们可以在程序运行时发现和使用类型信息. Java在运行时识别对象和类的信息的方式: (1)一种是RTTI,它假定 ...
- Java编程思想 学习笔记12
十二.通过异常处理错误 Java的基本理念是“结构不佳的代码不能运行”. Java中的异常处理的目的在于通过使用少于目前数量的代码来简化大型.可靠的程序的生成,并且通过这种方式可以使你更加自信:你的 ...
随机推荐
- 20150820 PROCEDURE 模板
USE [DB_H_F1]GO/****** Object: StoredProcedure [dbo].[sp_sys_user_add] Script Date: 08/19/2015 1 ...
- 第十六章:网络IPC:套接字
16.1.引言 上一章考查了各种Unix系统所提供的经典进程间通信(IPC)机制:管道.先进先出.消息队列.信号量以及共享内存.通过这些机制,同一台计算机上运行的进程可以相互通信.本章将考查不同计算机 ...
- malloc与kmalloc
在设备驱动程序中动态开辟内存,不是用malloc,而是kmalloc,或者用get_free_pages直接申请页.释放内存用的是kfree,或free_pages. 对于提供了MMU(存储管理器,辅 ...
- grails-domain-id 无生成策略,由程序控制
一 domain class 中标示 class Menu implements Comparable<Menu>{ String id; String name; } static co ...
- mysql计划任务
这两天一直遇见mysql计划任务的案例,今天我就给大家分享一个真是的实例: 1.创建计划任务的语法: create event 任务名称 on schedule at 时间周期 starts '年- ...
- 首先,定义一个Print类,它有一个方法void output(int x),如果x的值是1,在控制台打印出大写的英文字母表;如果x的值是2,在 控制台打印出小写的英文字母表。其次,再定义一个主类——TestClass,在主类 的main方法中创建Print类的对象,使用这个对象调用方法output ()来打印出大 小写英文字母表。
package lianxi; public class Print_1 { int x; Print_1(int x) { this.x = x; } void outPut() { String ...
- 向sql server 导入数据库
在sql server 中选择数据库.右键,还原数据库 选择源设备,点击添加,选中相应的数据库文件. 在目标数据库栏选择相应的数据库名称 点击下一步.
- (转)Genymotion安装virtual device的“unable to create virtual device, Server returned Http status code 0”的解决方法
网络原因无法下载virtual device,status 为0表示服务器没有响应.FQ下载吧,有VPN的小伙伴推荐这种. 或者直接手动下载ova虚拟机文件,然后将虚拟机文件导入到virtualbox ...
- Cheatsheet: 2013 09.01 ~ 09.09
.NET Multi Threaded WebScraping in CSharpDotNetTech .NET Asynchronous Patterns An Overview of Projec ...
- 曲线救国,解决Mac系统下,Android sdk下载失败的问题
Mac下翻_墙的问题 话说GFW屏蔽谷歌已经有一阵子了,最近打算在Mac系统下折腾个Android应用,备好了IDE,只欠SDK,无奈下载时因为GFW的缘故,总是失败,我心痛哉! 由于本人偏爱Mac系 ...