1、 Java的桌面应用
桌面应用一般仅仅需要JRE的支持就足够了。
2、 Java Web应用
Java的Web应用至少需要安装JDK和一个web容器(例如Tomcat),以及一个多用户数据库,Web应用至少分为三层:
Browser层:浏览器显示用户页面
Web层:运行Servlet/JSP
DB层:后端数据库,向Java程序提供数据访问服务
3、 Java企业级应用
企业级应用比较复杂,可以扩展到n层,最简单情况会分为4层:
Browser层:浏览器显示用户页面
Client层:Java客户端图形程序(或者嵌入式设备的程序)直接和Web层或者EJB层交互
Web层:运行Servlet/JSP
EJB层:运行EJB,完成业务逻辑运算
DB层:后端数据库,向Java程序提供数据访问服务
4、 Java嵌入式应用
Java嵌入式应用是一个方兴未艾的领域,从事嵌入式开发,需要从Sun下载J2ME开发包,J2ME包含了嵌入式设备专用虚拟机KVM,和普通的JDK中包含的JVM有所不同。另外还需要到特定的嵌入式厂商那里下载模拟器。
Java 程序员的独孤九剑
破剑式——《Effective Java Programming Language Guide》
破刀式——《Design patterns: Elements of Reusable Object Oriented Software》
破枪式——《Core J2EE Patterns》
破鞭式——《Refactoring: Improving the Design of Existing Code》
破索式——《AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis》
破掌式——《Analysis Patterns: Reusable Object Models》
破箭式——《Extreme Programming Explained: Embrace Change》
破气式——《Data Mining: Concepts and Techniques》
独孤九剑,有进无退!招招都是进攻,攻敌之不得不守。虽只一剑一式,却是变化无穷,学到后来,前后式融会贯通,更是威力大增,剑法的精要所在:“料敌机先”。
基础30条
1,final, finally, finalize的区别。
final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。finally是异常处理语句结构的一部分,表示总是执行。finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。
2,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?
可以继承其他类或完成其他接口,在swing编程中常用此方式。
3,Static Nested Class 和 Inner Class的不同,说得越多越好(面试题有的很笼统)。
Static Nested Class是被声明为静态(static)的内部类,它可以不依赖于外部类实例被实例化。而通常的内部类需要在外部类实例化后才能实例化。
4,&和&&的区别。
&是位运算符,表示按位与运算,&&是逻辑运算符,表示逻辑与(and).
5,HashMap和Hashtable的区别。
HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable.
6,Collection 和 Collections的区别。
Collection是集合类的上级接口,继承与他的接口主要有Set 和List.Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。
7,什么时候用assert。
1.4新增关键字(语法),用于测试boolean表达式状态,可用于调试程序。使用方法 assert ,表示如果表达式为真(true),则下面的语句执行,否则抛出AssertionError。另外的使用方式assert < boolean表达式>:,表示如果表达式为真,后面的表达式忽略,否则后面表达式的值用于AssertionError的构建参数。注意编译时要增加-source 1.4 参数,否则报错。]运行时要增加 –ea参数,否则assert行被忽略
8,GC是什么? 为什么要有GC?
GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。
9,swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?
switch(expr1)中,expr1是一个整数表达式。因此传递给 switch 和 case 语句的参数应该是 int、 short、 char 或者 byte。long,string 都不能作用于swtich。
10,Math.round(11.5)等於多少? Math.round(-11.5)等於多少?
Math.round(11.5)==12Math.round(-11.5)==-11round方法返回与参数最接近的长整数,参数加1/2后求其floor.
11,short s1 = 1; s1 = s1 + 1;有什么错?
short s1 = 1; s1 += 1;有什么错? short s1 = 1; s1 = s1 + 1; (s1+1运算结果是int型,需要强制转换类型)short s1 = 1; s1 += 1;(可以正确编译)
12,sleep() 和 wait() 有什么区别?
sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
13,数组有没有length()这个方法? String有没有length()这个方法?
数组没有length()这个方法,有length的属性。
String有有length()这个方法。
14,Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?
方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。
15,Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?
Set里的元素是不能重复的,那么用iterator()方法来区分重复与否。equals()是判读两个Set是否相等。
equals()和==方法决定引用值是否指向同一对象equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。
16,最常见到的runtime exception。
ArithmeticException, ArrayStoreException, BufferOverflowException, BufferUnderflowException, CannotRedoException, CannotUndoException, ClassCastException, CMMException, ConcurrentModificationException, DOMException, EmptyStackException, IllegalArgumentException, IllegalMonitorStateException, IllegalPathStateException, IllegalStateException,
ImagingOpException, IndexOutOfBoundsException, MissingResourceException, NegativeArraySizeException, NoSuchElementException, NullPointerException, ProfileDataException, ProviderException, RasterFormatException, SecurityException, SystemException, UndeclaredThrowableException, UnmodifiableSetException, UnsupportedOperationException
17,error和exception有什么区别?
error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。
exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。
18,List, Set, Map是否继承自Collection接口?
List,Set是
Map不是
19,abstract class和interface有什么区别?
声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例。不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现,否则它们也是抽象类为。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。
接口(interface)是抽象类的变体。在接口中,所有方法都是抽象的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽象的,没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否实现了接口。
20,abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?
都不能
21,接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)?
接口可以继承接口。抽象类可以实现(implements)接口,抽象类是否可继承实体类,但前提是实体类必须有明确的构造函数。
22,启动一个线程是用run()还是start()?
启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。
23,构造器Constructor是否可被override?
构造器Constructor不能被继承,因此不能重写Overriding,但可以被重载Overloading。
24,是否可以继承String类?
String类是final类故不可以继承。
25,当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
不能,一个对象的一个synchronized方法只能由一个线程访问。
26,try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?
会执行,在return前执行。
27,编程题: 用最有效率的方法算出2乘以8等於几?
有C背景的程序员特别喜欢问这种问题。
2 << 3
28,两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
不对,有相同的hash code。
29,当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
是值传递。Java 编程语言只由值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的。
30 . String s = new String("xyz");创建了几个String Object?
两个
"xyz" 是一个String 对象。
new String("xyz") 又new 出一个String对象。
简单APPLET
import java.applet.*;
public class Button2 extends Applet {
Button
b1 = new Button( "Button 1"),
b2 = new Button( "Button 2");
public void init() {
add(b1);
add(b2);
}
public boolean action(Event evt, Object arg) {
if(evt.target.equals(b1))
getAppletContext().showStatus( "Button 1");
else if(evt.target.equals(b2))
getAppletContext().showStatus( "Button 2");
// Let the base class handle it:
else
return super.action(evt, arg);
return true; // We've handled it here
}
}
JAVA编码问题的一些理解
1.在JSP程序中加入一条语句:
2.在URL请示字符串的编码问题。
如果通过GET/POST方法从客户端传递过来的信息中包含汉字信息,SERVLET/JSP无法得到正确的值。
我们在调用request.getParameter("param_name")前指定应用程序所希望的编码方式。
也就是request.setCharacterEcoding()即可
3.在不同的平台编码的问题是不同的。
在linux平台上的标准是Iso8859_1,而在win2k下是GBK的,这些是默认的标准,如果你的服务器不是这样的,那么编译的问题一定会有问题。本人就遇到这样的问题,两台LINUX服务器,一台lang=en,一台lang=en,UTF8,被我搞了N长时间才找到原因。
3.我本人用的最多的转换编码的一个类(在linux平台),几乎可以解决所有的编码问题。类的方法非常解决。主要就是asc2gb()和gb2asc()这两个类。
package com.whaic.tools;
import java.io.UnsupportedEncodingException;
public class ECov
{
public static String asc2gb(String asc){
String ret;
if(asc==null)return asc;
try{
ret=new String(asc.getBytes("ISO8859_1"),"GB2312");
}
catch(UnsupportedEncodingException e){
ret=asc;
}
return ret;
}
public static String gb2asc(String gb){
String ret;
if(gb==null)return gb;
try{
ret=new String(gb.getBytes("GB2312"),"ISO8859_1");
}
catch(UnsupportedEncodingException e){
ret=gb;
}
return ret;
}
}
4.读写文件时的中文问题:
Read::
FileInputStream fis = new FileInputStream(strInFile);
InputStreamReader isr = new InputStreamReader(fis, "GB2312");
Reader in = new BufferedReader(isr);
int ch;
while ((ch = in.read()) > -1) {
iCharNum += 1;
buffer.append((char)ch);
}
in.close();
Write::
FileOutputStream fos = new FileOutputStream(strOutFile);
Writer out = new OutputStreamWriter(fos, "Big5");
out.write(str);
out.close();
以上仅仅是本人是日常使用中遇到的一些问题和解决方案。由于国际化的工作并不是在国内完成的,所以在这些基本类发布之前,没有经过严格的测试,所以对中文字符的支持并不像 Java Soft 所声称的那样完美。Java 编程语言成长于网络世界,这就要求 Java 对多国字符有很好的支持。 Java 编程语言适应了计算的网络化的需求,为它能够在网络世界迅速成长奠定了坚实的基础。 Java 的缔造者 (Java Soft) 已经考虑到 Java 编程语言对多国字符的支持,只是现在的解决方案有很多缺陷在里面,需要我们付诸一些补偿性的措施。而世界标准化组织也在努力把人类所有的文字统一在一种编码之中,其中一种方案是 ISO10646 ,它用四个字节来表示一个字符。当然,在这种方案未被采用之前,还是希望 Java Soft 能够严格地测试它的产品,为用户带来更多的方便
开心词典
婉言相劝
克隆的控制
为消除克隆能力,大家也许认为只需将clone()方法简单地设为private(私有)即可,但这样是行不通的,因为不能采用一个基础类方法,并使其在衍生类中更“私有”。所以事情并没有这么简单。此外,我们有必要控制一个对象是否能够克隆。对于我们设计的一个类,实际有许多种方案都是可以采取的:
(1) 保持中立,不为克隆做任何事情。也就是说,尽管不可对我们的类克隆,但从它继承的一个类却可根据实际情况决定克隆。只有Object.clone()要对类中的字段进行某些合理的操作时,才可以作这方面的决定。
(2) 支持clone(),采用实现Cloneable(可克隆)能力的标准操作,并覆盖clone()。在被覆盖的clone()中,可调用super.clone(),并捕获所有违例(这样可使clone()不“掷”出任何违例)。
(3) 有条件地支持克隆。若类容纳了其他对象的句柄,而那些对象也许能够克隆(集合类便是这样的一个例子),就可试着克隆拥有对方句柄的所有对象;如果它们“掷”出了违例,只需让这些违例通过即可。举个例子来说,假设有一个特殊的Vector,它试图克隆自己容纳的所有对象。编写这样的一个Vector时,并不知道客户程序员会把什么形式的对象置入这个Vector中,所以并不知道它们是否真的能够克隆。
(4) 不实现Cloneable(),但是将clone()覆盖成protected,使任何字段都具有正确的复制行为。这样一来,从这个类继承的所有东西都能覆盖clone(),并调用super.clone()来产生正确的复制行为。注意在我们实现方案里,可以而且应该调用super.clone()——即使那个方法本来预期的是一个Cloneable对象(否则会掷出一个违例),因为没有人会在我们这种类型的对象上直接调用它。它只有通过一个衍生类调用;对那个衍生类来说,如果要保证它正常工作,需实现Cloneable。
(5) 不实现Cloneable来试着防止克隆,并覆盖clone(),以产生一个违例。为使这一设想顺利实现,只有令从它衍生出来的任何类都调用重新定义后的clone()里的suepr.clone()。
(6) 将类设为final,从而防止克隆。若clone()尚未被我们的任何一个上级类覆盖,这一设想便不会成功。若已被覆盖,那么再一次覆盖它,并“掷”出一个CloneNotSupportedException(克隆不支持)违例。为担保克隆被禁止,将类设为final是唯一的办法。除此以外,一旦涉及保密对象或者遇到想对创建的对象数量进行控制的其他情况,应该将所有构建器都设为private,并提供一个或更多的特殊方法来创建对象。采用这种方式,这些方法就可以限制创建的对象数量以及它们的创建条件——一种特殊情况是singleton(独子)方案。
(1) 实现Cloneable接口
(2) 覆盖clone()
(3) 在自己的clone()中调用super.clone()
(4) 在自己的clone()中捕获违例
这一系列步骤能达到最理想的效果。
深层克隆
class MyObject implements Cloneable {
int i;
MyObject( int ii) { i = ii; }
public Object clone() {
Object o = null;
try {
o = super.clone();
} catch (CloneNotSupportedException e) {
System.out.println( "MyObject can't clone");
}
return o;
}
public String toString() {
return Integer.toString(i);
}
}
public class LocalCopy {
static MyObject g(MyObject v) {
// Passing a handle, modifies outside object:
v.i++;
return v;
}
static MyObject f(MyObject v) {
v = (MyObject)v.clone(); // Local copy
v.i++;
return v;
}
public static void main(String[] args) {
MyObject a = new MyObject(11);
MyObject b = g(a);
// Testing handle equivalence,
// not object equivalence:
if(a == b)
System.out.println( "a == b");
else
System.out.println( "a != b");
System.out.println( "a = " + a);
System.out.println( "b = " + b);
MyObject c = new MyObject(47);
MyObject d = f(c);
if(c == d)
System.out.println( "c == d");
else
System.out.println( "c != d");
System.out.println( "c = " + c);
System.out.println( "d = " + d);
}
}
a == b a = 12 b = 12 c != d c = 47 d = 48
总之,克隆时要注意的几个关键问题是:要实现Cloneable接口,几乎肯定要调用super.clone(),以及注意将克隆设为public。
一旦对象变得可以克隆,从它衍生的任何东西都是能够克隆的,除非使用特殊的机制令其“关闭”克隆能力。
简单克隆
class Int {
private int i;
public Int( int ii) { i = ii; }
public void increment() { i++; }
public String toString() {
return Integer.toString(i);
}
}
public class Cloning {
public static void main(String[] args) {
Vector v = new Vector();
for( int i = 0; i < 10; i++ )
v.addElement( new Int(i));
System.out.println( "v: " + v);
Vector v2 = (Vector)v.clone();
// Increment all v2's elements:
for(Enumeration e = v2.elements();
e.hasMoreElements(); )
((Int)e.nextElement()).increment();
// See if it changed v's elements:
System.out.println( "v: " + v);
}
}
v: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] v: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
这个例子指出Vector的clone()方法不能自动尝试克隆Vector内包含的每个对象——由于别名问题,老的Vector和克隆的Vector都包含了相同的对象。
我们通常把这种情况叫作“简单复制”或者“浅层复制”,因为它只复制了一个对象的“表面”部分。实际对象除包含这个“表面”以外,还包括句柄指向的所有对象,
以及那些对象又指向的其他所有对象,由此类推。这便是“对象网”或“对象关系网”的由来。
别名问题
int i;
Demo(int ii) { i = ii; }
public static void main(String[] args) {
Demo x = new Demo(7);
Demo y = x; // Assign the handle
System.out.println("x: " + x.i);
System.out.println("y: " + y.i);
System.out.println("Incrementing x");
x.i++;
System.out.println("x: " + x.i);
System.out.println("y: " + y.i);
}
}
int i;
Demo(int ii) { i = ii; }
static void f(Demo handle) {
handle.i++;
}
public static void main(String[] args) {
Demo x = new Demo(7);
System.out.println("x: " + x.i);
System.out.println("Calling f(x)");
f(x);
System.out.println("x: " + x.i);
}
}
Calling f(x)
x: 8
绝对隐私
入门基本概念
原因是:
1).一个内部类的对象能够访问创建它的对象的实现,包括私有数据。
2).对于同一个包中的其他类来说,内部类能够隐藏起来。
3).匿名内部类可以很方便的定义回调。
4).使用内部类可以非常方便的编写事件驱动程序。
用GZIP进行简单压缩
import java.util.zip.*;
public static void main(String[] args) {
try {
BufferedReader in =
new BufferedReader(
new FileReader(args[0]));
BufferedOutputStream out =
new BufferedOutputStream(
new GZIPOutputStream(
new FileOutputStream("test.gz")));
System.out.println("Writing file");
int c;
while((c = in.read()) != -1)
out.write(c);
in.close();
out.close();
System.out.println("Reading file");
BufferedReader in2 =
new BufferedReader(
new InputStreamReader(
new GZIPInputStream(
new FileInputStream("test.gz"))));
String s;
while((s = in2.readLine()) != null)
System.out.println(s);
} catch(Exception e) {
e.printStackTrace();
}
}
}
糟糕透顶
文件过滤
public class DirList {
public static void main(String[] args) {
try {
File path = new File( ".");
String[] list;
if(args.length == 0)
list = path.list();
else
list = path.list( new DirFilter(args[0]));
for( int i = 0; i < list.length; i++)
System.out.println(list[i]);
} catch(Exception e) {
e.printStackTrace();
}
}
}
class DirFilter implements FilenameFilter {
String afn;
DirFilter(String afn) { this.afn = afn; }
public boolean accept(File dir, String name) {
return f.indexOf(afn) != -1;
}
}
快速阅读技巧
软件的生命性
软件是有生命的,这可能是老调重弹了,但是因为它事关分层架构的原由,反复强调都不过分。
一个有生命的软件首先必须有一个灵活可扩展的基础架构,其次才是完整的功能。
目前很多人对软件的焦点还是落在后者:完整的功能,觉得一个软件功能越完整越好,其实关键还是架构的灵活性,就是前者,基础架构好,功能添加只是时间和工作量问题,但是如果架构不好,功能再完整,也不可能包括未来所有功能,软件是有生命的,在未来成长时,更多功能需要加入,但是因为基础架构不灵活不能方便加入,死路一条。
正因为普通人对软件存在短视误区,对功能追求高于基础架构,很多吃了亏的老程序员就此离开软件行业,带走宝贵的失败经验,新的盲目的年轻程序员还是使用老的思维往前冲。其实很多国外免费开源框架如ofbiz compiere和slide也存在这方面陷阱,貌似非常符合胃口,其实类似国内那些几百元的盗版软件,扩展性以及持续发展性严重不足。
那么选择现在一些流行的框架如Hibernate、Spring/Jdonframework是否就表示基础架构打好了呢?其实还不尽然,关键还是取决于你如何使用这些框架来搭建你的业务系统。