Java编程思想(11~17)

【注:此博客旨在从《Java编程思想》这本书的目录结构上来检验本身的Java基础知识,只为笔记之用】java

第十一章 持有对象正则表达式

11.1 泛型和类型安全的容器》eg: List<String> 容器中能够插入该泛型类子类均可以放置进去
11.2 基本概念
  (1)Collection. 一个独立元素的序列,这些元素都服从一条或多条规则.List 必须按照插入的顺序保存元素,而Set不能有重复元素
    Queue按照排队规则来肯定对象产生的顺序
  (2)Map. 一组成对的"键值对"对象
11.3 添加一组元素
11.4 容器的打印
  ArrayList和LinkedList都是List类型按照插入的顺序保存元素;ArrayList优势在于随机访问;LinkedList 优势在于插入和移除元素
  HashSet 按照hash算法插入;TreeSet按照比较的升序保存对象;LinkedHashSet 按照被添加的顺序保存对象
11.5 List算法

11.6 迭代器编程

11.6.1 ListIterator》是一个更强大的Iterator的子类型,它只能用于各类List类型的访问;Iterator只能向前移动,ListIterator能够
双向移动。
11.7 LinkedList
11.8 Stack
11.9 Set 》可使用set类型来消除重复元素
11.10 Map
11.11 Queue
11.11.1 PriorityQueue
11.12 Collection和Iterator
11.13 Foreach与迭代器
11.13.1 适配器方法惯用法数组

 

第十二章 经过异常处理错误缓存

12.1 概念
12.2 基本异常
12.3 捕获异常
  12.3.1 try块
12.3.2 异常处理程序
12.4 建立自定义异常
  12.4.1 异常与记录日志
12.5 异常说明》在编译时强制检查的异常被称为被检查异常
12.6 捕获全部异常》catch exception
  12.6.1 栈轨迹
  12.6.2 从新抛出异常 》throw
  12.6.3 异常链》Throwable的子类中三种基本异常类提供了带cause参数的构造器:Error(Java虚拟机报告系统错误),Exception以及
RuntimeException安全

12.7 Java标准异常》Throwable 表示任何能够做为异常被抛出的类。Throwable对象能够分为两种类型:Error表示编译时和系统错误(除
特殊状况外,通常不用关心);Exception 表示被抛出的异常的基本类型,在Java类库,用户方法以及运行时故障中均可能抛出Exception。Java
开发人员关心的基本类型一般是Exception。
  12.7.1 特例:RuntimeException
12.8 使用finally进行清理
  12.8.1 finally用来作什么
  12.8.2 在return中使用finally
  12.8.3 缺憾:异常丢失
12.9 异常的限制
12.10 构造器
12.11 异常匹配
12.12 其余可选方式
  12.12.1 历史
  12.12.2 观点
  12.12.3 把异常传送给控制台
  12.12.4 把“被检查的异常”转换为“不检查的异常”》throw new RuntimeException(e);
12.13 异常使用指南
  (1)在恰当的级别处理问题(在知道该如何处理的状况下才捕获异常)
  (2)解决问题而且从新调用产生异常的方法
  (3)进行少量的修补,而后绕过异常发生的地方继续执行
  (4)用别的数据进行计算,以替代方法预计会返回的值
  (5)把当前运行环境下能作的事情尽可能作完,而后把相同的异常从新抛到更高层
  (6)把当前运行环境下能作的事情尽可能作完,而后把不一样的异常抛到更高层
  (7)终止程序
  (8)进行简化(若是你的异常模式使问题变得太复杂,那用起来会很是痛苦)
  (9)让类库和程序更安全架构

第13章 字符串app

13.1 不可变String
13.2 重载“+”与StringBuilder》当在Java中作字符串相加"+"时,底层会自动引入iava.lang.StringBuilder类
StringBuilder与StringBuffer相比较,后者是线程安全的
13.3 无心识的递归
13.4 String上的操做
13.5 格式化输出
  13.5.1 printf()
  13.5.2 System.out.format()
  13.5.3 Formatter类
  13.5.4 格式化说明符》其抽象语法:%[argument_index$][flags][width][.precision]conversiondom

  13.5.5 Formatter转换

 

  13.5.6 String.format()
13.6 正则表达式
  13.6.1 基础
  13.6.2 建立正则表达式

  13.6.3 量词

  13.6.4 Pattern和Matcher
  13.6.5 split()
13.6.6 替换操做
13.6.7 reset()
13.6.8 正则表达式与Java I/O》正则表达式搜索文件的内容
13.7 扫描输入》Scanner
  13.7.1 Scanner定界符
  13.7.2 用正则表达式扫描
13.8 StringTokenizer》可使用Scanner或正则表达式替代

 第14章

14.1 为何使用RTTI》(RTTI:在运行时识别一个对象的类型)
14.2 Class对象》Java使用Class对象来执行其RTTI,即便你正在执行的是相似转型的操做
每一个类都有一个Class对象;使用“类加载器”来生成类对象;类是在第一次使用时动态加载到JVM中的
获取Class对象:Class.forName() ;对象.getClass(); Class对象的newInstance()建立类对象,该类必须带有默认的构造器
  14.2.1 类字面常量》获取Class对象的另外一个方法:类名.class 如:String.class。使用这种方式不会自动初始化该Class对象
为了使用类而坐的准备工做包含三步骤:
  (1)加载,这是有类加载器执行的
  (2)连接 在连接阶段将验证类中的字节码,为静态域分配存储空间,而且若是必要的话,将解析这个类建立对其余类的引用
  (3)初始化 若是该类具备超类,则对其初始化,执行静态初始化器和静态初始化块
因此,初始化操做被延迟到对静态方法(构造器隐式是静态的)或者很是态数静态进行首次引用时才执行
  14.2.2 泛化的Class引用》Class<T>
  Class<?> 优于普通的Class,尽管它们等价,可是Class<?>不会产生编译器警告信息;
  Class<?>的好处是它表示你并不是是碰巧或因为疏忽,而是使用了一个非具体的类引用
  14.2.3 新的转型语法》Class对象.cast()
  Class中两个使用不常使用或没有任何用处的新特性是:Class对象.cast()接受参数对象并将其转换为Class引用的类型;
  Class.asSubclass()容许你将一个类对象转型为更加具体的类型。
14.3 类型转换前先作检查》instanceof; class<? extends 基类>
  14.3.1 使用类字面常量》类名.class
  14.3.2 动态的instanceof》Class.isInstance方法提供了一种动态测试对象的途径
  14.3.3 递归计数
14.4 注册工厂
14.5 instanceof 与 Class的等价性
14.6 反射:运行时的类信息》RTTI(Run-Time Type Identification)和反射之间真正的区别在于:对于RTTI来讲,编译器在编译时
打开和检查.class文件。而对于反射机制来讲,.class文件在编译时是不能够获取的,因此在运行时开发和检查.class文件
  14.6.1 类方法提取器》Class的getMethods()和getConstructors()方法分别返回Method对象数组和Constructor对象数组
14.7 动态代理
14.8 空对象
  14.8.1 模拟对象与桩
14.9 接口与类型信息》javap一个随JDK发布的反编译器
    javap -private 类名 》eg:javap -private java.lang.String
14.10 总结反射式强大的,能够经过修改权限调用哪些被设置成private的方法

第15章 泛型

15.1 与C++比较

15.2 简单泛型》Java泛型的核心概念是告诉编译器想要什么类型,而后编译器帮你处理一切细节
      泛型的主要目的是用来指定容器要持有什么类型的对象,而且有编译器来保证类型的正确性

    public class Generate<T>{
        private T t;
        Generate(T t){ this.t=t;}
    }

  15.2.1 一个元组类库
  须要在一个方法就能返回多个不一样类型的对象,但是return 语句只容许返回单个对象,解决办法就是再建立一个对象,
用它来包含想要返回的多个类型对象,当能够在每次须要的时候专门建立一个类为此工做,可是有了泛型咱们就可以一次性解决
这个问题,同时咱们还能再编译器确保类型的安全。这个概念就是元组(tuple),它将多个对象存储在一个单一对象中,这个容器
对象容许读取其中的元素,可是不容许向其中存放新的对象。元组能够任意长度,以下两个类型的元组:

    public class TwoTuple<A,B>{//这个类能够装载两个类型的
        public finale A first;
        public finale B second;
        TwoTuple(A a,B b){
            this.first=a;
            this.second=b;
        }
    }
    public class TestTuple{
        static TwoTuple<String,Integer> f(){//该方法就返回了String,Integer两种类型的对象
            return new TwoTuple<String,Integer>("hi",70);
        }
        public static void main(String[] args){
            f();
        }
    }

  15.2.2 一个堆栈类
  15.2.3 RandomList
15.3 泛型接口

    public interface Generator<T>  {T next();}
    public class Fibonaci implements Generator<Integer>{
        private int count=0;
        public Integer next(){return fib(count++);}
        private Integer fib(int n){
            if(n<2)return 1;
            return fib(n-2)+fib(n-1);
        }
        public static void main(String[] args){
            Fibonaci f=new Fibonaci();
            for(int i=0;i<10;i++){
                System.out.println(f.next());
            }
        }
    }

15.4 泛型方法 》要定义泛型方法只须要将泛型参数置于返回值以前

    public class GenericMethods{
        public <T> void f(T t) {
            System.out.println(t.getClass().getSimpleName());
        }
        public static void main(String[] args) {
            GenericMethods chapterA = new GenericMethods();
            chapterA.f("");
        }
    }

  15.4.1 杠杆利用类型参数推断
  显示的类型说明:点操做符与方法名之间插入尖括号,而后把类型置于尖括号内
  若是是在定义该方法类的内部,必须在点操做符以前使用this关键字
  若是使用的static方法,必须在点操做符以前加上类名

            public class ExplicitTypeSpecification{
                static void f(Map<Person,List<Pet>> petPeople){}
                public static void(String[] args){
                    f(XXXX.<Person,List<Pet>>map());
                }
            }

  15.4.2 可变参数与泛型方法

    public class GenericVarargs{
            public static <T> List<T> makeList(T... args){
                List<T> result=new ArrayList<T> ();
                for(T item: args){
                    result.add(item);
                }
                return result;
            }
            public static void main(String[] args){
                List<String> ls=makeList("A");
                System.out.println(ls);
                ls=makeList("A","B","C");
                System.out.println(ls);
            }
        }

  15.4.3 用于Generator的泛型方法
  15.4.4 一个通用的Generator
  15.4.5 简化元组的使用

 public class Tuple{
        public static <A,B> TwoTuple<A,B> tuple(A a,B b){
            return new TwoTuple<A,B>(a,b);
        }
    }

  15.4.6 一个Set使用工具

15.5 匿名内部类

    class Teller{
        private static long counter=1;
        private final long id=counter++;
        public String toString(){return "Teller "+id;}
        public static Generator<Teller> generator=new Generator<Teller>(){....}
    }

15.6 构建复杂模型

    public class TupleList<A,B,C,D> extends ArrayList<A,B,C,D>{
        public static void main(String[] args){
            TupleList<Vehicle,Amphibian,String,Integer> tl=new TupleList<Vehicle,Amphibian,String,Integer>();
            .....
        }                
    }

15.7 擦除的神秘之处

    public class ErasedTypeEquivalence{
        public static void main(String[] args){
            Class c1 = new ArrayList<String>().getClass();
            Class c2 = new ArrayList<Integer>().getClass();
            System.out.println(c1 == c2);
        }    
    }

输入的结果是:true
在这里咱们很容易的认为ArrayList<String>和ArrayList<Integer>是不一样的类型,即输出的结果为false,但是Java运行
出来的结果是true,这说明Java认为他们是同一个类型,为何呢? 

 

在看为何钱,咱们先来看看Class类中的getTypeParameters这个方法的定义和做用
注释的意思是:返回一个TypeVariable类型的数组,TypeVarible表示泛型中使用的类型变量或者类型参数
    /**
     * Returns an array of {@code TypeVariable} objects that represent the
     * type variables declared by the generic declaration represented by this
     * {@code GenericDeclaration} object, in declaration order.  Returns an
     * array of length 0 if the underlying generic declaration declares no type
     * variables.
     *
     * @return an array of {@code TypeVariable} objects that represent
     *     the type variables declared by this generic declaration
     * @throws java.lang.reflect.GenericSignatureFormatError if the generic
     *     signature of this generic declaration does not conform to
     *     the format specified in
     *     <cite>The Java&trade; Virtual Machine Specification</cite>
     * @since 1.5
     */
    @SuppressWarnings("unchecked")
    public TypeVariable<Class<T>>[] getTypeParameters() {
        ClassRepository info = getGenericInfo();
        if (info != null)
            return (TypeVariable<Class<T>>[])info.getTypeParameters();
        else
            return (TypeVariable<Class<T>>[])new TypeVariable<?>[0];
    }

再看以下程序:

咱们看到输入的并非具体的类型名,而是只是无用的占位符的标识符

所以,这说了一个现实是:在泛型代码的内部,没法得到任何有关泛型参数类型的信息  

  15.7.1 C++的方式》模板被实例化时,模板代码知道其模板参数的类型
    可是针对泛型的擦除能够用extends 定义一个上限:List<T extends Parent>,那么编译器在进行泛型类型参数
    擦除时将擦除到它的第一个边界,即就像“Parent”替换“T“同样

  15.7.2 迁移兼容性
  为了减小潜在的关于擦除的混淆,必须清楚的认识到这不是一个语言的特性.它是Java泛型实现的一种折中,由于泛型不是
在Java语言一开始出现时就有的;若是泛型在Java 1.0中就已经有了,那么这个特性就不会使用擦除来实现了。擦除减小了泛
型的泛化性,虽然泛型仍然颇有用,只是没有咱们想象的那么有用了
在基于擦除的现实中,泛型类型被看成第二类类型处理,即不能在某些重要的上下文环境中使用的类型。泛型只在静态类型
检查期间才出现,在此以后,程序中全部的泛型类型都将被擦除,替换为它们的非泛型上界。例如:List<T> 将为擦除为List,
而普通的类型变量,在未经过"extends"指定上限状况下将被擦除为Object
擦除机制的核心动机是使采用泛化的代码可使用费泛化的代码
  15.7.3 擦除的问题
擦除的主要正当理由是从非泛化代码到泛化代码的转变过程,以及不破坏现有的类库的状况下,将泛型融入Java语言
其代价就是:不能用于显示的引用运行时类型的操做中,如转型,instanceof操做和new 表达式;由于全部的参数类型信息
都丢失了。因此,不管什么时候,当你在编写泛型代码时,必须时刻提醒本身,这些只是看起来好像拥有关于参数的类型信息

  15.7.4 边界处的动做
15.8 擦除的补偿
  15.8.1 建立类型实例
  15.8.2 泛型数组》因为泛型擦除》因此通常的解决方案是在任何想要建立泛型数组的地方都是用ArrayList
15.9 边界》 xxx<T extends SuperClass>

          或class ColoredDimension<T extends Dimension&HashColor>{}

          或class ColoredDimension<T extends Dimension & HashColor & Weight>{}

          或        

            class HoleItem<T>{}
            class Colored<T extends HasColor> extends HoleItem<T>{}


15.10 通配符》class Demo<? extends Uper>
  15.10.1 编译器有多聪明》编译器并无想象中的那么聪明

public class CompilerIntellience{
    List<? extends Fruit> flist=Arrays.asList(new Apple());
    Apple a=(Apple)flist.get(0);//没有警告
    flist.contains(new Apple()); //Argument is "Object"
    flist.indexOf(new Apple()); //Argument is "Object"
}

  15.10.2 逆变》超类通配符:super

public class SuperTypeWildcards{
    static void wirteTo(List<? super Apple> apples){
        apples.add(new Apple());
        apples.add(new Jonathan());
        //apples.add(new Fruit()); //Error
    }
}

  15.10.3 无界通配符》?

public class UnboundedWildcards{
    static Map map1;
    static Map<?,?> map2;
    static Map<String,?> map3;
}

  List和List<?>是不一样的:List能够持有任何类型的组合,而List<?>将持有具备某种具体类型的同构集合

  在使用确切类型替代通配符类型的好处是能够用泛型参数来作更多的事,可是使用通配符使得你必须接受范围更宽的参数化类型做为参数

  15.10.4 捕获转换
15.11 问题
  15.11.1 任何基本类型都不能做为类型参数

  15.11.2 实现参数化接口》一个类不一样实现同一个泛型接口的两中变体,因为擦除的缘由,这两个变体会成为相同的接口

  interface Payable<T>{}
  class Employee implements Payable<Employee>{}
  class Hourly extends Employee implements Payable<Horly> {} 
  //这个类不能编译,由于擦除会将Payable<Horly>和Payable<Employee>简化为相同的类Payable,这样就意味着
  //在重复两次实现相同的接口

  15.11.3 转型和警告》使用带有泛型参数的转型或instanceof不会有任何效果
  15.11.4 重载

public class UserList<W,T>{
    void f(List<T> v){}
    void f(List<W> v){}
}//因为擦除的缘由,重载方法产生相同的方法签名,所以当擦除的参数不能产生惟一的参数列表时,必须提供明显的区别:
public class UserList<W,T>{
    void f1(List<T> v){}
    void f2(List<W> v){}
}

  15.11.5 基类劫持了接口
15.12 自限定的类型
  15.12.1 古怪的循环类型
  15.12.2 自限定

  自限定所作的就是要求在继承关系中下面这样定义:
  class A extends SelfBounded<A>{}
  这回强制要求将正在定义的类看成参数传递给基类
  其意义保证类型参数必须与正在定义的类相同

  15.12.3 参数协定
15.13 动态类型安全

  将子类的类型的对象放置到将要检查基类类型的受检查容器中是没有问题的

15.14 异常

  因为擦除缘由,泛型应用于异常是很是有限的.catch语句不能捕获泛型类型的异常,由于在编译器和运行时都必须知道异常的确切类型.
泛型也不能直接或间接继承自Throwable.可是泛型参数可能会在一个方法的throws字句中用到.这可让你编写随检查型异常的类型而
发生变化的泛型代码

interface Processor<T, E extends Exception> {}

15.15 混型  

  混型最基本的概念是混合多个类的能力以产生一个能够表示混型中全部类型的类,其价值之一是能够将特性和行为一致的应用于多个类中.
若是想在混型总修改某些东西,这些修改将会应用于混型所应用的全部类型之上.

  15.15.1 C++中的混型
  15.15.2 与接口混合

interface Basic{
    private String value;
    public void set(String val);
    public String get();
}
interface SerivalNumbered{long getSerialNumber();}
interface TimeStamped{long getStamp();}

class BasicTmp implements Basic{
    private String value;
    public void set(String val){value=val;}
    public String get(){return value;}
}

class Mixin extends BasicTmp implements SerivalNumbered,TimeStamped{
    ....
}

  15.15.3 使用装饰器模式
  15.15.4 与动态代理混合
15.16 潜在类型机制》不要求静态或动态类型检查

  在Java中由于泛型是后期才添加到Java中的,所以没有任何机会能够去实现任何类型的潜在类型机制,所以Java不支持这种特性

15.17 对缺少潜在类型机制的补偿
  15.17.1 反射》可使用反射来实现相似的潜在类型机制的特性
  15.17.2 将一个方法应用于序列
  15.17.3 当你并未碰巧拥有正确的接口时
  15.17.4 用适配器仿真潜在的类型机制
15.18 将函数对象用做策略
15.19 总结:转型真的如此之遭吗?
  15.19.1 进阶读物

第16章
16.1 数组为何特殊
  在泛型和自动包装机制以前,数组与其余容器之间的区别有三方面:效率,类型和保存基本类型的能力
在Java中数组是一种效率最高的存储和随机访问对象引用序列的方式,它是简单的线性序列,这使得访问的速度很是快速,
可是这种快速所付出的代价就是数组对象的大小被固定了,而且在生命周期中不可改变。
随着自动包装机制的出现,如今容器能够与数组同样方便的用于基本类型,数组惟一的优势就是效率
16.2 数组是以第一级对象》数组标识符其实只是一个引用
16.3 返回一个数组
16.4 多维数组
16.5 数组与泛型

    class ClassParameter<T>{//参数化类
        public T[] f(T[] arg){return arg;}
    }
    
    class MethodParameter{//参数化方法
        public static <T> T[] f(T[] arg){return arg;}
    }
    
    public class ParameterArrayType{
        public static void main(String[] args){
            Integer[] ints={1,2,3,4};
            Double[] doubles={1.1,2.2,3.3,4.4,5.5};
            Integer[] ints2=new ClassParameter<Integer>().f(ints);
            Double[] double2=new ClassParameter<Double>().f(doubles);
        }
    }

Peel<Banana>[] peels=new Peel<Banana>[10];//报错
尽管不能建立实际的持有泛型的数组对象,可是能够建立非泛型的数组
List<String>[] ls;
List[] la=new List[20];
ls=(List<String>)la;//"Unchecked" warning

通常而言,泛型在类或方法的边界处颇有效,而在类或方法的内部,擦除一般会是泛型变得不适用 

16.6 建立测试数据
  16.6.1 Arrays.fill()
  16.6.2 数据生成器
  16.6.3 从Genenrator中建立数组
16.7 复制数组
  16.7.1 复制数组》System.arraycopy()
  16.7.2 数组的比较》Arrays.equals()
  16.7.3 数组元素比较》java.lang.Comparable接口 ; compareTo()方法
  16.7.4 数组排序》Arrays.sort()
  16.7.5 在已排序的数组中查找》Arrays.binarySearch()

第17章 容器深刻研究
17.1 完整的容器分类法

17.2 填充容器》Collections.nCopies() ;Collections.fill()
  17.2.1 一种Generator解决方案
  17.2.2 Map生成器
  17.2.3 使用Abstract类
17.3 Collection的功能方法

17.4 可选操做
  17.4.1 为获支持的操做》Arrays.asList()会生成一个基于固定大小数组的List
注意:Arrays.asList()的结果做为构造器的参数传递给任何Collection(或者使用
addAll()方法,或Collections.addAll()静态方法),这样能够生成容许使用全部方法的普通容器
17.5 List的功能方法
17.6 Set和存储顺序

在HashSet上打星号表示,若是没有其余限制,它就是默认的选择,由于它对速度进行了优化

  17.6.1 SortedSet

17.7 队列
  17.7.1 优先级队列
  17.7.2 双向队列
17.8 理解Map
  17.8.1 性能

  17.8.2 SortedMap》键处于排序状态
  17.8.3 LinkedHashMap
17.9 散列与散列码》自定义类重载hashCode()和equals()
  17.9.1 理解hashCode()
  17.9.2 为速度而散列
  17.9.3 覆盖hashCode()

17.10 选择接口的不一样实现
  17.10.1 性能测试架构
  17.10.2 对List的选择
  17.10.3 微基准测试的危险
  17.10.4 对Set的选择
  17.10.5 对Map的选择
17.11 实用方法

  17.11.1 List的排序和查询》使用Collections中的方法  17.11.2 设定Collection或Map为不可修改》Collections.unmodifiableCollection(c)  17.11.3 Collections或Map的同步控制》Collections.synchronizedCollection(c) ConcurrentHashMap、CopyOnWriteArrayList和CopyOnWriteArraySet都使用了能够避免ConcurrentModificationException的技术17.12 持有引用   对象可得到则垃圾回收器不会释放它;若不可得到,那么回收就是安全 SoftReference、WeakReference和PhantomReference由强到弱排序,对应不一样级别的“可得到性”.SoftReference用以实现内存敏感的高速缓存。WeakReference是为实现“规范映射”而设计的,它不妨碍垃圾回收器回收映射的“键”。“规范映射”中的对象的实例能够在程序的多处被同时使用,以节省存储空间。PhantomReference用以调度回收器前的清理工做,它比Java终止机制更灵活。 PhantomReference只能依赖于ReferenceQueue   17.12.1 WeakHashMap》它被用来保存WeakReference17.13 Java 1.0/1.1的容器   17.13.1 Vector和Enumeration   17.13.2 Hashtable   17.13.3 Stack   17.13.4 BitSet

相关文章
相关标签/搜索