20145107 《Java程序设计》第九周学习总结
20145107 《Java程序设计》第九周学习总结
教材学习内容总结
在本周,我们进行了书中第十六,十七,十八章的学习。本周的学习目标是:
了解JDBC架构
掌握JDBC架构
掌握反射与ClassLoader
了解自定义泛型和自定义枚举
会使用标准注解
第十六章:
JDBC是用于执行SQL的解决方案,开发人员使用JDBC的标准接口,数据库厂商则使用JDBC接口进行操作,本章讲的就是JDBC的一些基础操作。JDBC标准主要分为两个部分:JDBC应用程序开发者接口以及JDBC驱动程序开发者接口。如果你的应用程序需要联机数据库,就是调用JDBC应用开发接口。如果将来要换为Oracle数据库,只要置换Oracle驱动程序。
而厂商在操作JDBC时,可以按照操作方式将驱动程序分为四种类型:
- 1.JDBC-ODBC Bridge Driver:
这是由微软公司主导的数据库连接标准,基本上,,JDBC是按照ODBC的参考制定而来,所以,ODBC在微软的操作系统上最为成熟,在office Access中的数据库就是使用ODBC。虽然ODBC与JDBC有很多的相同通用之处,但两者并非是一一对应的,所以部分调用无法直接转换因此存在一些功能的限制。 - 2.Native API Driver:
Native API Driver会以原生的方式条用数据库提供的原生链接库,JDBC的方法调用都会转换为原生链接库中相关的数据库调用。 - 3.JDBC NET-Driver
这个类型的JDBC驱动程序会将JDBC方法调用转换为特定的网络协议调用,目的是远程与数据库特定的中介服务器或组件进行协议操作。 - 4.Native Protocol Driver
这种类型的驱动程序的主要作用是将JDBC转化为特定的网络协议,所以此程序也可以使用原生的Java技术来实现,所以,这种类型的驱动程序可以跨平台,在效能上也有很好的表现。
第十七章:
反射:
- 1.class与class文档:
在Java的程序中,只有真正需要某个类时才会加载对应的.class文档,而不是在程序启动时就加在所有的类。所以大多数的用户只会使用应用程序的部分资源,在需要某些功能的时候才会加载对应的资源,这样可以使程序的运行变得更有效率。
java.lang.Class的实例的代表了Java应用程序运行时加载的.class文档,类,接口编译后哦都会生成相应的.class文档。我们可以使用Object中的getchar()方法,或者是通过class常量取得每个对象对应的class对象。在取得对应的对象后,就可以操作class对象的公开方法取的类的信息就像下面的程序:
package Reflection;
import static java.lang.System.out;
public class ClassInfo {
public static void main(String[] args) {
Class clz = String.class;
out.println("类别名称:" + clz.getName());
out.println("是否为接口:" + clz.isInterface());
out.println("是否为基本类型:" + clz.isPrimitive());
out.println("是否为数组对象:" + clz.isArray());
out.println("父类名称:" + clz.getSuperclass().getName());
}
}
程序运行的程序截图如下:
some类定义了static的区块系统默认首次加载都会执行静态区块,通过在文本模式显示下可以了解如何生成加载.class文件。就像下面的程序:
package Reflection;
public class some {
static {
System.out.println("载入 Some.class 档案");
}
}
package Reflection;
import static java.lang.System.out;
public class SomeDemo {
public static void main(String[] args) {
some s;
out.println("宣告 Some 参考名称");
s = new some();
out.println("生成 Some 实例");
}
}
程序生成图如下所示:
- 2.使用Class.forName:
在某些应用中,无法实现知道开发人员使用那个类,我们可以使用Class.forName()方法实现加载动态类,可以使用字符串指定名称活的累的相关信息:
package Reflection;
import static java.lang.System.out;
public class InfoAbout {
public static void main(String[] args) {
try {
Class clz = Class.forName(args[0]);
out.println("类的名称:" + clz.getName());
out.println("是否为接口:" + clz.isInterface());
out.println("是否为基本类型:" + clz.isPrimitive());
out.println("是否为数组:" + clz.isArray());
out.println("父类:" + clz.getSuperclass().getName());
} catch (ArrayIndexOutOfBoundsException e) {
out.println("没有指定名称");
} catch (ClassNotFoundException e) {
out.println("找不到指定类别 " + args[0]);
}
}
}
程序运行的截图如下所示:
- 3.使用class建立对象:
如果知道类的名称,可以使用new关键字建立实例,如果事先不知道类的名称,我们可是使用class.forName()动态加载.class文件,在取得方法后再利用其newInstance来取得实例。这种方法在书中用电影拍摄放映的例子很好的进行了解释。首先,我们先定义出影片链接库该有的功能:
package cc.openhome;
public interface Player {
void play(String video);
}
然后,可以先完成动画的操作播放:
package cc.openhome;
import java.util.Scanner;
public class MediaMaster {
public static void main(String[] args) throws ClassNotFoundException,
InstantiationException, IllegalAccessException {
String playerImpl = System.getProperty("cc.openhome.PlayerImpl");
Player player = (Player) Class.forName(playerImpl).newInstance();
System.out.print("输入想播放的影片:");
player.play(new Scanner(System.in).nextLine());
}
}
在上面的类名称中,并没有把Player的类定义的很固定,这可以再启动程序时通过系统属性来指定,其操作如下:
package cc.openhome;
public class ConsolePlayer implements Player {
@Override
public void play(String video) {
System.out.println("正在播放 " + video);
}
}
建立ClassLoder实例:
JVM的ClassLoader分三层,分别为Bootstrap ClassLoader
,Extension ClassLoader
,System ClassLoader
,他们不是类继承的父子关系,是逻辑上的上下级关系。
Bootstrap ClassLoader
是启动类加载器,它是用C++编写的,从%jre%/lib
目录中加载类,或者运行时用-Xbootclasspath
指定目录来加载。
Extension ClassLoader
是扩展类加载器,从%jre%/lib/ext
目录加载类,或者运行时用-Djava.ext.dirs
制定目录来加载。
System ClassLoader
,系统类加载器,它会从系统环境变量配置的classpath
来查找路径,环境变量里的.表示当前目录,是通过运行时-classpath或-Djava.class.path
指定的目录来加载类。
下面有个简单的范例可以指定加载路径,测试class实例是否为同一对象:
package Reflection;
import static java.lang.System.out;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class ClassLoaderDemo {
public static void main(String[] args) {
try {
String path = args[0];
String clzName = args[1];
Class clz1 = loadClassFrom(path, clzName);
out.println(clz1);
Class clz2 = loadClassFrom(path, clzName);
out.println(clz2);
out.printf("clz1 与 clz2 为%s实例",
clz1 == clz2 ? "相同" : "不同");
} catch (ArrayIndexOutOfBoundsException e) {
out.println("沒有指定类别加载路径与名称");
} catch (MalformedURLException e) {
out.println("载入路径错误");
} catch (ClassNotFoundException e) {
out.println("找不到指定的类別");
}
}
private static Class loadClassFrom(String path, String clzName)
throws ClassNotFoundException, MalformedURLException {
ClassLoader loader = new URLClassLoader(new URL[] {new URL(path)});
return loader.loadClass(clzName);
}
}
程序的截图如下:
十八章:
- 1.自定义泛型:
泛型的本质就是将数据类型也参数化, 普通方法的输入参数的值是可以变的,但是类型(比如: String)是不能变的,它使得了在面对不同类型的输入参数的时候我们要重载方法才行。泛型就是将这个数据类型也搞成跟参数的值一样可以变。 - 2.自定义枚举:
枚举是一种规范它规范了参数的形式,这样就可以不用考虑类型的不匹配并且显式的替代了int型参数可能带来的模糊概念 枚举像一个类,又像一个数组。Enum作为Sun全新引进的一个关键字,看起来很象是特殊的class, 它也可以有自己的变量,可以定义自己的方法,可以实现一个或者多个接口。枚举具有如下特性:
1.它不能有public的构造函数,这样做可以保证客户代码没有办法新建一个enum的实例。
2.所有枚举值都是public , static , final的。注意这一点只是针对于枚举值,我们可以和在普通类里面定义 变量一样定义其它任何类型的非枚举变量,这些变量可以用任何你想用的修饰符。
3.Enum默认实现了java.lang.Comparable接口。
4.Enum覆载了了toString方法,因此我们如果调用Color.Blue.toString()默认返回字符串”Blue”.
5.Enum提供了一个valueOf方法,这个方法和toString方法是相对应的。调用valueOf(“Blue”)将返回Color.Blue.因此我们在自己重写toString方法的时候就要注意到这一点,一把来说应该相对应地重写valueOf方法。
6.Enum还提供了values方法,这个方法使你能够方便的遍历所有的枚举值。
7.Enum还有一个oridinal的方法,这个方法返回枚举值在枚举类种的顺序,这个顺序根据枚举值声明的顺序而定,这里Color.Red.ordinal()返回0。
本周代码托管截图
本周代码链接
本周代码统计截图
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 200/200 | 2/2 | 20/20 | |
第二周 | 100/300 | 1/3 | 18/38 | |
第三周 | 200/500 | 1/4 | 22/60 | |
第四周 | 250/750 | 1/5 | 30/90 | |
第五周 | 450/1200 | 1/6 | 20/110 | |
第六周 | 400/1600 | 2/8 | 30/140 | |
第七周 | 150/1750 | 2/10 | 30/170 | |
第八周 | 500/2250 | 2/12 | 30/200 | |
第九周 | 230/2580 | 2/14 | 30/230 |