复用类

《Thinking In Java》复用类

组合与继承

  • 组合:在新的类中产生现有类的对象。
  • 继承:按照现有类的类型来创建新类,无需改变现有类的形式,采用现有类的形式并在其中添加新的代码。
组合:
public class TestDemo1 {
public static void main(String[] args) {
  A a = new A();
  a.f1();
}
}
class  A{
public void f1(){
B b = new B("哈登");//组合
b.f2();
System.out.println(b);// 如果不覆写B类中的toString(),那么就会输出b对象的地址
}
}
class B{
private int age;
private String name ;
public B(String name){
this.name = name;
this.age=28;
}
public void f2(){
System.out.println("姓名为:"+name+" ,年龄为:"+age);
}

@Override
public String toString() {
return name;
}
}

打印结果

这里在B类的构造方法中初始化了age的值,如果将this.age=28注释掉,那么年龄为0.

关于初始化

1.类中域为基本类型时,默认自动初始化为0

2.类中域为引用类型时,默认自动初始化为null

初始化位置

1.在定义对象的地方。意味着在调用构造器之前进行初始化

2.在类的构造器中

3.实例初始化

4.延迟初始化(惰性初始化)在使用对象之前

看一下具体代码

public class ChuShiHua {
public static void main(String[] args) {
Student student = new Student("Messi");
System.out.println(student);
}
}

class Student {
//1.在定义对象的地方。意味着在调用构造器之前进行初始化
  private String name1="Ronaldo";
  private String name2,name3,name4;
  //2.在类的构造器中
  public Student(String name2){
  this.name2 = name2;
  }
  // 3.实例初始化
{
name3="Alice";
}

 // 4.延迟初始化(惰性初始化)在使用对象之前
@Override
public String toString() {
  if(name4==null){
  name4="Peter";
  }
return name1+" "+name2+" "+name3+ " "+ name4;
}
}

继承
class Fu{
public Fu(){
System.out.println("这是父类构造");
}
}
class Son extends  Fu{
public Son(){
System.out.println("这是子类构造");
}
}

public class JiCheng {
public static void main(String[] args) {
 new Son();
}
}

这里Son类继承了Fu类。关键字是extends.无论如何,父类构造总是先被初始化,然后再初始化子类构造。

子类默认调的是父类的无参构造,如果想要调用父类的有参构造,那么在子类构造的第一句话写上super(..)

class Fu{
int age;
public Fu(){
System.out.println("aaa");
}
public Fu(int age){
this.age = age;
System.out.println("这是父类构造"+this.age);
}
}
class Son extends  Fu{
int i;
public Son(int i){
**super(20);**
this.i  = i ;
System.out.println("这是子类构造"+ i);
}
}

public class JiCheng {

public static void main(String[] args) {
 new Son(10);
}
}
protected关键字
  • 对于类的用户而言,是私有的
  • 对于其子类或者同一包的类而言,是可以访问的

在F类中定义了一个protected修饰的方法,在Z类中可以访问的。

向上转型

继承的最大用处并不是复用类,而是多态。多态又是基于继承的。

class Instrument{
static void play(Instrument e){
System.out.println("通过向上转型"+e);
}
}
public class Wind  extends  Instrument{
public static void main(String[] args) {
Wind wind = new Wind();
Instrument.play(wind);
}
}

在play()方法中,将Wind对象传入到父类Instrument的play()方法中,照样能够打印出Wind对象。用父类的引用去接收子类的对象,其指向的是子类对象。

final关键字

final所描述的对象是无法改变的。主要用在类,方法,数据中。

数据

告知编译器这块数据是无法改变的。

1.一个永不改变的编译时常量—减轻了运行时的负担

2.一个运行时被初始化的值,而你并不需要它被改变

3.一个即是static 又是 final 的数据描述的是只占据一块不能改变的存储空间

4.当final作用在基本类型的时候,指的是数值无法改变。当fianl作用于对象的引用时,指的是对象的引用不变,但对象本身还是可以改变的。

class FinalData{
int num = 1;
   public final  int age1 =20;

   /*
   * 1.用static final 修饰的变量应该字母全部大写
   * 2.用public可以无限制被访问
   * 3.static:强调只有一份
   * 4.final: 说明它是一个常量
   *
   * */
   public static final int AGE = 10;
}
public class FinalTest {
public static void main(String[] args) {
FinalData fd = new FinalData();
System.out.println(fd.age1);//输出20
//  fd.age1=30; 由于age是final所修饰的基本类型,数值不能被改变。

 final FinalData fdFinal  = new FinalData();
 fdFinal.num=30;
System.out.println(fdFinal.num);//打印30

   //无法编译,因为fdFinal的引用是不能被改变的 
   // fdFinal = new FinalData();
}
}
final参数
  class FinalData{
public void fun(final  int i){
  //  i++;无法编译,因为i是final类型,值无法改变
}
public void fun2(final FinalData f){
f.fun(1);
  //  f = new FinalData(); 无法编译,因为f的引用不可变
}
}
public class FinalTest {
public static void main(String[] args) {

}
}
final方法

作用:

  • 把方法锁定,防止任何继承类修改它的含义
  • 效率

类中所以的private方法都是final类型的,由于无法取用private方法,所以也就无法覆盖它。

   class GrandFather{
private   final void fun(){
System.out.println("11");
}
}
class  Father extends GrandFather{
private   final void fun(){
System.out.println("22");
}
}
class  Son extends  Father{
public  final void fun(){
System.out.println("33");
}
}

public class FinalMethodTest {

public static void main(String[] args) {
  Son s = new Son();
  s.fun();//打印33

GrandFather f = s;

//f.fun();  无法编译   

}
}

类内所有 private 方法都自动成为 final。由于我们不能访问一个 private 方法,所以它绝对不会被其他方
法覆盖(若强行这样做,编译器会给出错误提示)。可为一个 private 方法添加 final 指示符,但却不能为
那个方法提供任何额外的含义。

final类

final类描述的是该类没有子类,无法被继承。

可以看到上面代码报错,无法编译,原因是父类被声明为final类型。

在一个类中如果被声明为final类型,那么该类的方法隐式的都被声明为final类型。

初始化及类的加载

class Fu {
private int age =70;
private String name;
public static String address = "崇明岛";
static {
System.out.println("这是父类的static静态块");
}
public Fu(){
System.out.println("这是父类构造");
}
public void fu(){
System.out.println(age+name+address);
}
}
class  Zi extends  Fu{
private int age=30 ;
private String name;
public static String address = "海南岛";
static {
System.out.println("这是子类的static静态块");
}
public Zi(){
System.out.println("这是子类构造");
}
public void zi(){
System.out.println(age+name+address);
}
}


public class CSHTest extends  Zi{
private int age=10 ;
private String name;
public static String address = "台湾岛";
static {
System.out.println("这是孙类的static静态块");
}
public CSHTest(){
System.out.println("这是孙类构造");
}
public void test(){
System.out.println(age+name+address);
}

public static void main(String[] args) {
 CSHTest t = new CSHTest();
 t.test();
}
}

首先执行CSHTEST类的main方法,类加载器查找CSHTEST编译后的代码.class,发现其有一个父类Zi,于是加载Zi,发现它又有一个父类,于是再加载Fu,此时,根基类中的static初始化(static修饰符描述的方法只执行一次),然后是下一个导出类,以此类推。此种方式很重要。因为导出类初始化有可能依赖于父类的初始化。

此时类已经加载完毕了。现在可以创建对象了。首先,对象中的基本类型都被初始化为0,对象的引用都被初始化为null,然后,基类的构造器就被调用,在本例中,是默认调用的,默认调用super(),如果想指定调用有参构造,那么自己写super(Type Args).

总结就是:加载父类的静态块—>加载子类静态块—->加载父类的构造—>加载子类构造

声明

所写内容是《Thinking In Java》读书笔记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值