Thinking In Java Part07(容器、简单的容器分类、类加载器)

1、Collection和Iterator
	Collection是描述所有序列容器的共性的根接口,它可能会被认为是一个“附属接口”,即因为要表示其他若干个接口的共性而出现的接口。AbstractCollection是Collection的默认实现。
	使用接口描述的一个理由是它可以使我们能够创建更通用的代码,通过针对接口而非具体实现来编写代码,我们的代码可以应用于更多的对象类型。
2、适配器方法惯用法
	如果现有一个Iterable类,想要添加一个或多种在foreach语句中使用这个类的方法,,例如希望可以选择以向前的方向或是向后的方向迭代一个单词列表。如果直接继承这个类,并覆盖Iterator()方法,你只能替换先有的方法,而不能实现选择。
	一种解决方案是所谓适配方法的惯用法。提供特定的接口满足foreach语句,希望在默认的前向迭代器的基础上,添加产生反向迭代器的能力,因此不能使用覆盖,而是添加一个能够产生Iterable对象的方法,该对象可以用于foreach语句,这使得我们可以提供多种使用foreach的方式。
	class ReversibleArrayList<T> extends ArrayList<T> {
	    public ReversibleArrayList(Collection<T> c) {
	        super(c);
	    }

	    public Iterable<T> reversed() {
	        return new Iterable<T>() {
	            @Override
	            public Iterator<T> iterator() {
	                return new Iterator<T>() {
	                    int current = size() - 1;

	                    @Override
	                    public boolean hasNext() {
	                        return current > -1;
	                    }

	                    @Override
	                    public T next() {
	                        return get(current--);
	                    }
	                };
	            }
	        };
	    }
	}

	public class AdapterMethod {
	    public static void main(String[] args) {
	        ReversibleArrayList<String> strings = new ReversibleArrayList<>(Arrays.asList("hh oo ll www".split(" ")));
	        for(String s:strings){
	            System.out.println(s + "");
	        }
	        System.out.println();
	        for (String s: strings.reversed()){
	            System.out.println(s + "");
	        }
	    }
	}
	如果直接将对象置于foreach当中,会得到默认的前向迭代器。但是如果在对象上调用reversed方法,会产生不同的行为
	Arrays.asList()产生的List对象会使用底层数组作为其物理实现,只要你执行的 操作会修改这个List,并且你不想原有的数组被修改,那么就应该在另外的一个容器中创建一个副本。
3、持有对象的方式
	3.1、数组将数字与对象联系起来。它保存类型明确的对象,查询对象时,不需要对结果做类型转换。它可以是多维的,可以保存基本类型的数据。但是,数组一旦生成,其容量就不能改变。
	3.2、Collection保存单一的元素,而Map保存相关联的键值对。有了Java的泛型,你就可以指定容器中存放的对象类型,因此你就不会将错误类型的对象放置到容器中,并且在从容器中获取元素时,不必进行类型转换。各种Collection和各种Map都可以在你向其中添加更多的元素时,自动调整其尺寸。容器不能持有基本类型,但是自动包装机制会仔细地执行基本类型到容器中所持有的包装器类型之间的双向转换。
	3.3、像数组一样,List也建立数字索引与对象的关联,因此,数组和List都是排好序的容器。List能够自动扩充容量。
	3.4、如果要进行大量的随机访问,就使用ArrayList,如果要经常从表中间插入或删除元素,则应该使用LinkedList。
	3.5、各种Queue以及栈的行为,由LinkedList提供支持
	3.6、Map是一种将对象(而非数字)与对象相关联的设计。HashMap设计用来快速访问;而TreeMap保持“键”始终处于排序状态,所以没有HashMap快。LinkedHashMap保持元素插入的顺序,但是也通过散列提供了快速访问能力。
	3.7、Set不接受重复元素。HashSet提供最快的查询速度,而TreeSet保持元素处于排序状态。LinkedHashSet以插入顺序保存元素。
	3.8、新程序中不应该使用过时的Vector、Hashtable和Stack。
4、容器分类
	其实只有四种容器:Map、List、Set、Queue 各有2个到三个实现版本.
	除了TreeSet之外的所有Set都拥有与Collection完全一样的接口。List和Collection存在着明显的不同,尽管List所要求的方法都在Collection中。另一方面,在Queue接口中的方法都是独立的,在创建具有Queue功能的实现时,不需要使用Collection方法。最后,Map和Collection之间的唯一重叠就是Map可以使用entrySet()和values()方法来产生Collection。
	RandomAccess附着到了ArrayList上,而没有附着到LinkedList上。可以根据所使用的特定List而动态修改其行为的算法提供了信息。

简单的容器分类

5、通过异常处理错误
	Java的基本理念是“结构不佳的代码不能运行”。
	改进的错误恢复机制是提供代码健壮性的最强有力的方式。Java使用异常来提供一致的错误报告模型,使得构建能够与客户端代码可靠地沟通问题。
	Java中的异常处理的目的在于通过使用少于目前数量的代码来简化大型、可靠的程序的生成。
	使用异常所带来的另一个相当明显的好处是,它往往能降低错误处理代码的复杂度。因为使用异常,那就不必在方法调用出进行检查,因为异常机制将保证能够捕获这个错误。
	异常最重要的方面之一就是如果发生问题,它们将不允许程序沿着正常的路径继续走下去。C没有任何办法可以强制程序在出现问题时停止在某条路径上运行下去,因此我们有可能会较长时间地忽略了问题。异常允许我们强制程序停止运行,并告诉我们出现了什么问题,或者强制程序处理问题,并返回到稳定状态。
6、终止与恢复
	异常处理理论上有两种基本模型。Java支持终止模型(是Java和C++所支持的模型)。在这种模型中,将假设错误非常关键,以至于程序无法返回到异常发生的地方继续执行。一旦异常被抛出,就表明错误已无法挽回,也不能回来继续执行。
	另一种称为恢复模型。意思是异常处理程序的工作是修正错误,然后重新尝试调用出问题的方法,并认为第二次能成功。对于恢复模型,通常希望异常被处理之后能继续执行程序。如果想要用Java实现类似恢复的行为,那么在遇见错误时就不能抛出异常,而是调用方法来修正该错误。或者,把try块放在while循环中,这样就不断地进入try块,直到得到满意的结果。
	虽然恢复模型开始显得很吸引人,但不是很实用。最主要的原因可能是它所导致的耦合:恢复性的处理程序需要了解异常抛出的地点,这势必要包含依赖于抛出位置的非通用型代码。这增加了代码编写和维护的难度,对于异常可能会从许多地方抛出的大型程序来说,更是如此。
7、栈轨迹
	printStackTrace()方法锁提供的信息可以通过getStackTrace()方法来直接访问,这个方法将返回一个由栈轨迹中的元素所构成的数组,其中每一个元素都表示栈中的一桢。元素0是栈顶元素,并且是调用序列中的租后一个方法调用(这个Throwable被创建和抛出之处)。数组中的最后一个元素和栈底是调用序列中的第一个方法调用。
8、异常链
	在捕获一个异常后抛出另一个异常,并且希望把原始异常的信息保存下来,这杯称为异常链。在JDK1.4之前,从程序员必须自己编写代码来保存原始异常的信息。现在Throwable的子类在构造器中可以接受一个cause(因由)对象作为参数。这个cause就用来表示原始异常,这样通过把原始异常传递给新的异常,使得即使在当前位置创建并抛出了新的异常,也能听过这个异常链追踪到异常最初发生的位置。
	在Throwable的子类中,只有三种基本的异常类提供了带cause参数的构造器。是Error(用于Java虚拟机报告系统错误)、Exception以及RuntimeException。如果要把其他类型的异常链接起来,应该使用InitCause()方法而不是构造器。
9、“被检查的异常”和强静态类型检查对开发健壮的程序的好处实际上来自:
	不在于编译器是否会强制程序员去处理错误,而是要有一致的、使用异常来报告错误的模型。
	不在于什么时候进行检查,而是一定要有类型间抽查。也就是说,必须检查程序使用正确的类型,至于这种强制施加于编译时还是运行时,没有关系。
10、异常使用情况
	10.1、在恰当的级别处理问题(在知道该如何处理的情况下才捕获异常)
	10.2、解决问题并且重新调用产生异常的方法。
	10.3、进行少许修补,然后绕过异常发生的地方继续执行。
	10.4、用别的数据进行计算,以代替方法预计会返回的值。
	10.5、把当前运行环境下能做的事情尽量做完,然后把相同的异常重抛到更高层。
	10.6、把当前运行环境下能做的事情尽量做完,然后把不同的异常抛到更高层。
	10.7、终止程序
	10.8、进行简化(如果异常模式使问题变得动太复杂,那用起来会非常痛苦和烦人)
	10.9、让类库和程序更安全。(既是在调试做短期投资,也是在为程序的健壮性做长期投资)
11、异常的处理优点
	其中之一是使得我们可以在某处集中精力处理你要解决的问题,而在另一处处理你编写的这段代码中产生的错误。
12、字符串
	字符串操作是计算机程序设计中最场景的行为。
	String对象时不可变的,Stirng类中每一个看起来会修改String值的方法,实际上都是创建了一个全新的String对象,以包含修改后的字符串内容。而最初的String对象则丝毫未动。
13、重载"+"与StringBuilder
	在编译String s= "abc"+"cc";的时候编译器会自动引入java.lang.StringBuilder,虽然源代码中没有使用,但是编译器自主使用了它,因为更高效。
14、RTTI(Run-Time Type Identification)
	运行时类型信息使得我们可以在程序运行时发现和使用类型信息。
	Java有两种方式让我们在运行时识别对象和类的信息:
		传统的RTTI:假定我们在编译时已经知道了所有的类型
		反射机制:允许我们在运行时发现和使用类的信息。
15、类加载器
	类是程序的一部分,每个类都有一个Class对象。每当编写并且编译了一个新类,就会产生一个Class对象(更恰当地说是被保存在一个同名的.class文件中)。为了生成这个类对象,运行这个程序的Java虚拟机(JVM)将使用被称为“类加载器”的子系统。
	类加载器子系统实际上可以包含一条类加载器链,但是只有一个原生类加载器,它是JVM实现的一部分。原生类加载器加载的是所谓的可信类,包括Java API类,它们通常是从本地盘加载的。在这条链中,通常不需要添加额外的类加载器,但是如果你有特殊的需求(例如以某种特殊的方式加载类,以支持Web服务器应用,或者在网络中下载类),那么你可以挂接额外的类加载器。
	所有的类都是在对其第一次使用时,动态加载到JVM中的,当程序创建第一个对类的静态成员的引用时,就会加载这个类。这个证明构造器也是类的静态方法,即使在构造器之前没有使用static关键字。因此,使用new操作符创建类的新对象也会被当中对类的静态成员的引用。
	类加载器首先检查这个类的Class对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名查找.class文件(例如,某个附加类加载器可能会在数据库中查找字节码)。在这个类的字节码被加载时,它们会接受验证,以确保其没有被破坏,并且不包含不良Java代码(这个Java中用于安全防范目的的措施之一)。
	一旦某个类的Class对象被载入内存,它们就被用来创建这个类的所有对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值