Thinking In Java第十四章“Type Information”(1-10)

练习1:(1)在ToyTest.java中,将Toy的默认构造器注释掉,并解释发生的现象。

//: typeinfo/toys/ToyTest.java
// Testing class Class.
package typeinfo.toys;
import static net.mindview.util.Print.*;

interface HasBatteries {}
interface Waterproof {}
interface Shoots {}

class Toy {
  // Comment out the following default constructor
  // to see NoSuchMethodError from (*1*)
  Toy() {}
  Toy(int i) {}
}

class FancyToy extends Toy
implements HasBatteries, Waterproof, Shoots {
  FancyToy() { super(1); }
}

public class ToyTest {
  static void printInfo(Class cc) {
    print("Class name: " + cc.getName() +
      " is interface? [" + cc.isInterface() + "]");
    print("Simple name: " + cc.getSimpleName());
    print("Canonical name : " + cc.getCanonicalName());
  }
  public static void main(String[] args) {
    Class c = null;
    try {
      c = Class.forName("typeinfo.toys.FancyToy");
    } catch(ClassNotFoundException e) {
      print("Can't find FancyToy");
      System.exit(1);
    }
    printInfo(c);   
    for(Class face : c.getInterfaces())
      printInfo(face);
    Class up = c.getSuperclass();
    Object obj = null;
    try {
      // Requires default constructor:
      obj = up.newInstance();
    } catch(InstantiationException e) {
      print("Cannot instantiate");
      System.exit(1);
    } catch(IllegalAccessException e) {
      print("Cannot access");
      System.exit(1);
    }
    printInfo(obj.getClass());
  }
} /* Output:
Class name: typeinfo.toys.FancyToy is interface? [false]
Simple name: FancyToy
Canonical name : typeinfo.toys.FancyToy
Class name: typeinfo.toys.HasBatteries is interface? [true]
Simple name: HasBatteries
Canonical name : typeinfo.toys.HasBatteries
Class name: typeinfo.toys.Waterproof is interface? [true]
Simple name: Waterproof
Canonical name : typeinfo.toys.Waterproof
Class name: typeinfo.toys.Shoots is interface? [true]
Simple name: Shoots
Canonical name : typeinfo.toys.Shoots
Cannot instantiate
*///:~

     结果是抛出一个实例化异常InstantiationException,原因是没有找到无参构造器来实例化对象。为什么要找无参构造器呢?因为你丫的没给传参数啊,当然默认去找用无参构造器。

练习2:(2)将新的interface加到ToyTest.java中,看看这个程序是否能正确检测出并加以显示
     可以。

练习3:(2)将Rhomboid(菱形)加入Shape.java中,创建一个Rhomboid,将其向上转型为Shape,然后向下转型为Rhomboid。试着将其向下转型为Circle,看看会发生什么。

public class Shapes {
    public static void main(String[] args) {
        List<Shape> shapeList = Arrays.asList(new Circle(),new Square(),new Triangle(),new Rhomboid());
        for (Shape shape : shapeList) {
            shape.draw();
        }
        //向上转型为shape
        Shape shape = new Rhomboid();
        //向下转型Rhomboid
        Rhomboid r = (Rhomboid) shape;
        //再向下转型为Circle
        //Circle c = (Circle)shape;
        //编译时不会报错,但是运行时候会报错,报的是ClassCastException,原因是强制类型转换对象,必须要有继承关系,这个话题下面会提到~简单讲的话,就是A—继承—>B,C-继承->B,但是,A、C之间并没有继承关系,所以不能类型转换,会报错。
    }
}

下面就讲一下强制类型转换这个问题,试问,必须有互相继承关系的才能强制类型转换吗?
不一定,这样说不严谨。 如果是强制转换变量类型 ,就不需要继承 .如果是强制转换对象,那肯定要继承.毕竟继承是多态的基础!


练习4:(2)修改前一个练习,让你的程序在执行向下转型之前先运用instanceof检查类型。(如果是,就不执行)

    public static void main(String[] args) {
        List<Shape> shapeList = Arrays.asList(new Circle(), new Square(),
                new Triangle(),new Rhomboid());
        for (Shape shape : shapeList) {
            shape.draw();
        }
        // 向上转型为shape
        Shape shape = new Rhomboid();
        // 向下转型Rhomboid
        Rhomboid r = (Rhomboid) shape;
        // 向下转型之前进行instanceof检查
        Circle c = null;
        if (shape instanceof Circle) {
            c = (Circle) shape;
        } else {
            System.out.println("形状不是圆的!");
        }
    }/* Output:
Square.draw()
Triangle.draw()
Rhomboid.draw()
形状不是圆的!
*///:~

练习5:(3)实现Shapes.java中的rotate(Shape)方法,让它能判断它所旋转的是不是Circle(如果是,就不执行)。<经过查阅,已经修正~>

package typeinfo; 
import java.util.*; 

abstract class RShape { 
  void draw() { System.out.println(this + ".draw()"); } 
  abstract public String toString(); 
  void rotate(int degrees) { 
    System.out.println("Rotating " + this + 
      " by " + degrees + " degrees"); 
  } 
} 

class RCircle extends RShape { 
  public String toString() { return "Circle"; } 
  void rotate(int degrees) { 
    throw new UnsupportedOperationException(); 
  } 
} 

class RSquare extends RShape { 
  public String toString() { return "Square"; } 
} 

class RTriangle extends RShape { 
  public String toString() { return "Triangle"; } 
} 

public class Shapes{ 
  static void rotate(List<RShape> shapes) { 
    for(RShape shape : shapes) 
      if(!(shape instanceof RCircle)) 
        shape.rotate(45); 
  } 

  public static void main(String[] args) { 
    List<RShape> shapes = Arrays.asList( 
      new RCircle(), new RSquare(), new RTriangle() 
    ); 
    rotate(shapes); 
  } 
} /* Output: 
Rotating Square by 45 degrees 
Rotating Triangle by 45 degrees 
*///:~ 

练习6:(4)修改Shapes.java使这个程序能将某个特定类型的所有形状都“标示”出来(通过设标示)。每一个导出的Shape类的toString()方法应该能够指出Shape是否被标示。

package Exam;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

class HShape {
    boolean highlighted = false;

    public void highlight() {
        highlighted = true;
    }

    public void clearHighlight() {
        highlighted = false;
    }

    void draw() {
        System.out.println(this + " draw()");
    }

    public String toString() {
        return getClass().getName()
                + (highlighted ? " highlighted" : " normal");
    }

    static List<HShape> shapes = new ArrayList<HShape>();

    public HShape() {
        shapes.add(this);
    }

    static void highlight1(Class<?> type) {
        for (HShape shape : shapes) {
            if (type.isInstance(shape)) {
                shape.highlight();
            }
        }
    }

    static void clearHighlight1(Class<?> type) {
        for (HShape shape : shapes) {
            if (type.isInstance(shape)) {
                shape.clearHighlight();
            }
        }
    }

    static void forEach(Class<?> type, String method) {
        try {
            Method m = HShape.class.getMethod(method, (Class<?>[]) null);
            for (HShape shape : shapes) {
                if (type.isInstance(shape)) {
                    m.invoke(shape, (Object[]) null);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    static void highlight2(Class<?> type) {
        forEach(type, "highlight");
    }

    static void clearHighlight2(Class<?> type) {
        forEach(type, "clearHighlight");
    }
}

class HCircle extends HShape {
}

class HSquare extends HShape {
}

class HTriangle extends HShape {
}

public class E06_Highlight {
    public static void main(String[] args) {
        List<HShape> shapes = Arrays.asList(new HCircle(), new HSquare(),
                new HTriangle(), new HSquare(), new HTriangle(), new HCircle(),
                new HCircle(), new HSquare());
        HSquare.highlight1(HCircle.class);
        HSquare.highlight2(HCircle.class);
        for (HShape shape : shapes) {
            shape.draw();
        }
        System.out.println("**************");
        HSquare.highlight1(HShape.class);
        HSquare.highlight2(HShape.class);
        for (HShape shape : shapes) {
            shape.draw();
        }
        System.out.println("**************");
        HShape.clearHighlight1(ArrayList.class);
        HShape.clearHighlight2(ArrayList.class);
        for (HShape shape : shapes) {
            shape.draw();
        }
    }
}/*
Exam.HCircle highlighted draw()
Exam.HSquare normal draw()
Exam.HTriangle normal draw()
Exam.HSquare normal draw()
Exam.HTriangle normal draw()
Exam.HCircle highlighted draw()
Exam.HCircle highlighted draw()
Exam.HSquare normal draw()
**************
Exam.HCircle highlighted draw()
Exam.HSquare highlighted draw()
Exam.HTriangle highlighted draw()
Exam.HSquare highlighted draw()
Exam.HTriangle highlighted draw()
Exam.HCircle highlighted draw()
Exam.HCircle highlighted draw()
Exam.HSquare highlighted draw()
**************
Exam.HCircle highlighted draw()
Exam.HSquare highlighted draw()
Exam.HTriangle highlighted draw()
Exam.HSquare highlighted draw()
Exam.HTriangle highlighted draw()
Exam.HCircle highlighted draw()
Exam.HCircle highlighted draw()
Exam.HSquare highlighted draw()
*///:~

     在main方法中,通过给对象设置标示(例子中是HCircle,HShape,ArrayList),指定特定形状的标示,经过检查是否为shape的实例对象后对各种形状的对象设标示。最后由提toString()打印出来。

练习7:(3)修改SweetShop.java,使每种类型对象的创建由命令行参数控制。即,如果命令行是“java SweetShop Candy”,那么只有Candy对象被创建。注意你是如何通过命令行参数来控制加载哪个Class对象的。

class Candy {
    static {
        System.out.println("Loading Candy");
    }
}

class Gum {
    static {
        System.out.println("Loading Gum");
    }
}

class Cookie {
    static {
        System.out.println("Loading Cookie");
    }
}

public class SweetShop {
    public static void main(String[] args) throws Exception {
        for (String string : args) {
            Class.forName(string);
        }
    }
} /* Output: 
首先在命令行执行:javac SweetShop.java 把其编译成.class文件
然后在命令行执行:java SweetShop Candy即,输出为: Loading Candy
在命令行执行:java SweetShop Candy Cookie,输出为Loading Candy,(/n)Loading Cookie
*///:~

即在命令行可以传参,在main方法中根据所传的参数判断调用的方法~

练习8:(5)写一个方法,令它接受任一对象作为参数,并能够递归打印出该对象所在的继承体系中的所有类。

package typeinfo;

public class E08_RecursiveClassPrint {
    static void printClasses(Class<?> c) {
        if (c == null) {
            return;
        } else {
            System.out.println(c.getName());
        }
        for (Class<?> k : c.getInterfaces()) {
            System.out.println("Interface" + k.getName());
            printClasses(k.getSuperclass());
        }
        printClasses(c.getSuperclass());
    }

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < args.length; i++) {
            System.out.println("Displaying " + args[i]);
            printClasses(Class.forName(args[i]));
            if (i < args.length - 1) {
                System.out.println("===================");
            }
        }
    }
}/*
Displaying Circle
Circle
Shape
java.lang.Object
*///:~

这个比较麻烦,在命令行中敲javac编译后,敲java E08_RecursiveClassPrint Circle之前还要先编译一下Shapes.java,最好要在同一个目录下,然后才会打印以上信息~

练习9:(5)修改前一个练习,让这个方法使用Class.getDeclaredFields()来打印一个类中的域的相关信息。

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;

import static net.mindview.util.Print.*;

interface Iface {
    int i = 47;

    void f();
}

class Base implements Iface {
    String s;
    double d;

    @Override
    public void f() {
        System.out.println("Base.f");
    }
}

class Composed {
    Base b;
}

class Derived extends Base {
    Composed c;
    String s;
}

public class E09_GetDeclaredFields {
    static Set<Class<?>> alreadyDisplayed = new HashSet<Class<?>>();

    static void printClasses(Class<?> c) {
        // getSuperclass() 对象返回空
        if (c == null) {
            return;
        } else {
            print(c.getName());
            Field[] fields = c.getDeclaredFields();
            if (fields.length != 0) {
                print("Fields:");
            }
            for (Field field : fields) {
                print("   " + field);
            }
            for (Field field : fields) {
                Class<?> k = field.getType();
                if (!alreadyDisplayed.contains(k)) {
                    printClasses(k);
                    alreadyDisplayed.add(k);
                }
            }
            // 打印这个类实现的接口
            for (Class<?> k : c.getInterfaces()) {
                print("interfaces:" + k.getName());
                printClasses(k.getSuperclass());
            }
            printClasses(c.getSuperclass());
        }
    }

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < args.length; i++) {
            print("Displaying " + args[i]);
            printClasses(Class.forName(args[i]));
            if (i < args.length - 1) {
                print("===============");
            }
        }
    }
}/*
编译完命令行输入:java E09_GetDeclaredFields Derived
Displaying Derived
Derived
Fields:
   Composed Derived.c
   java.lang.String Derived.s
Composed
Fields:
   Base Composed.b
Base
Fields:
   java.lang.String Base.s
   double Base.d
java.lang.String
Fields:
   private final char[] java.lang.String.value
   private int java.lang.String.hash
   private static final long java.lang.String.serialVersionUID
   private static final java.io.ObjectStreamField[] java.lang.String.serialPersi
stentFields
   public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_OR
DER
   private static final int java.lang.String.HASHING_SEED
   private transient int java.lang.String.hash32
[C
interfaces:java.lang.Cloneable
interfaces:java.io.Serializable
java.lang.Object
int
long
[Ljava.io.ObjectStreamField;
interfaces:java.lang.Cloneable
interfaces:java.io.Serializable
java.lang.Object
java.util.Comparator
interfaces:java.io.Serializable
interfaces:java.lang.Comparable
interfaces:java.lang.CharSequence
java.lang.Object
double
interfaces:Iface
java.lang.Object
java.lang.Object
Base
Fields:
   java.lang.String Base.s
   double Base.d
interfaces:Iface
java.lang.Object
*///:~

该程序使用一个有趣的类层次结构的接口和复杂类型的组合。
这里,HashSet保持输出整齐,只显示一次字段。练习10可以帮助您理解输出

练习10:(3)写一个程序,使它能判断char数组究竟是个基本类型,还是个对象。

package typeinfos;

import static net.mindview.util.Print.*;

public class E10_PrimitiveOrTrue {
    public static void main(String[] args) {
        char[] ac =  "Hello,World!".toCharArray();
        print("ac.getClass():"+ac.getClass());
        print("ac.getClass().getSuperclass():"+ac.getClass().getSuperclass());
        char c = 'c';
        //!c.getClass();        //不能这样写,基本类型不是真正的对象
        int[] ia  = new int[3];
        print("ia.getClass():"+ia.getClass());
        long[] la = new long[3];
        print("la.getClass():"+la.getClass());
        double[] da  = new double[3];
        print("da.getClass():"+da.getClass());
        String[] sa = new String[3];
        print("sa.getClass():"+sa.getClass());
        E10_PrimitiveOrTrue[] pot = new E10_PrimitiveOrTrue[3];
        print("pot.getClass():"+pot.getClass());
        //多维数组
        int[][][] threed = new int[3][][];
        print("threed.getClass():"+threed.getClass());
    }
}/*
ac.getClass():class [C
ac.getClass().getSuperclass():class java.lang.Object
ia.getClass():class [I
la.getClass():class [J
da.getClass():class [D
sa.getClass():class [Ljava.lang.String;
pot.getClass():class [Ltypeinfos.E10_PrimitiveOrTrue;
threed.getClass():class [[[I
*///:~

     通过定义一个String类型对象调用的toCharArray()方法创建一个char类型的数组。注意到你能够调用getClass()方法和getSuperclass()方法因为它是一个真正类的对象。但是如果你想要为一个基本类型变量来去调用getClass()方法,例如char c这个变量,那么编译器就会报错——不是所有元素都是对象(记住这个论断,当别人说Java是个“纯(pure)”面向对象的语言的时候)

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 《Thinking in Java 》第四版是Bruce Eckel所撰写的一本Java编程入门书籍。本书作为一本深度和广度都非常适合初学者的参考书,在Java编程教材占有重要的地位。本书分为14个部分,从Java的基础语法到高级面向对象编程阐述,再到常用API、异常处理、泛型等各个方面都有详细的介绍和案例说明。整本书同时也以应用为导向,侧重于培养读者在实际开发思考的能力,提高读者的编程效率和质量。 对于初学者来说,本书可以帮助读者理解Java编程语言的基础理论,掌握基本的编程知识和技能,对Java编程语言的特点和优势有更深入的认识。本书还提供了许多实例和练习题,使学习者能够更快地掌握Java编程语言,并对其进行应用。而对于熟悉Java的开发者来说,本书也是一本优秀的参考书。无论是源码、设计模式、Java高级特性等方面的知识,本书都有详细的说明和示例代码。此外,本书还为读者提供了Java世界最新的技术和最佳实践。总之,《Thinking in Java》第四版是一本非常适合Java编程学习和实践的入门书籍,值得一读。 ### 回答2: Thinking in Java第四版英文是一本非常优秀的编程指南,它以Java语言为主题,全面介绍了Java编程语言的各种特性和用法,是Java编程的必备工具书。本书从Java编程的基础知识、对象和类、继承和多态、接口和内部类、异常、泛型和集合、输入和输出、注解、反射和代理、高级主题和Java8新功能等方面逐一讲解,每个知识点都循序渐进,全面深入,让读者能够真正掌握Java编程的精髓。 本书的特点在于对Java编程思想的阐述和深化。它在讲解Java语法的同时,为读者演示了如何通过面向对象的设计思想来编写Java程序。每个章节都伴随有丰富的示例代码,并且有详尽的解释注释,每一处都可以清晰易懂地讲解相应的知识点和技巧。这样的设计结构,可以大幅提高读者的学习效率,让读者在学习的同时,也可以获得Java编程的实战经验。 总之,Thinking in Java第四版英文是一本非常经典且值得阅读的Java编程教材,适合各种水平的读者使用,尤其适合想深入学习Java编程的人使用。其涉及的知识点十分广泛,既有基础知识,也有高深技术,且内容详实丰富、易于理解,该书是Java编程领域几乎每个开发人员都应该把它当作必读的工具书之一。 ### 回答3: 《Thinking in Java第四版英文》是一本非常优秀的Java编程技术书籍。本书详细讲解了Java语言的各类知识,从基础语法到高级技巧、开发过程等等。同时,该书还配有大量的例子和实战练习,让读者能够更加深入地理解和掌握所学的知识。 通过阅读《Thinking in Java第四版英文》,读者可以了解到Java的基本数据类型、控制语句、继承和多态等核心概念。同时,该书还深入讲解了Java的面向对象编程、异常处理、集合框架、IO、多线程、网络编程等各个方面,涵盖了Java编程的方方面面。 本书不仅具有广泛的知识面,还具有很强的实用性。在学完每个章节后,作者都提供了大量的实例代码和实践练习,让读者能够更好地理解并应用所学的知识。 总之,《Thinking in Java第四版英文》是一本非常优秀的Java编程技术书籍,是Java程序员必备的参考书籍。读者可以通过该书学到Java语言的核心知识,也能够获得实践经验和提高自己编程技能的机会。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值