??xml version="1.0" encoding="utf-8" standalone="yes"?> http://www.ibm.com/developerworks/cn/java/j-tiger08104/ 跟踪无法预期的运行时异常可能是一件又慢又费力的事情,只获得默认线E名U和堆栈跟踪通常是不够的。在 驯服 Tiger q一期专栏中QJava 开发h?John Zukowski 向您展示了如何通过替代默认行ؓ来定制输出。他q对比了通过l分 虽然我们不想创徏在无法预期时抛出q行时异常的E序Q但q种情况q是会发生——尤其是W一ơ运行复杂程序时。通常是用默认行为、打印堆栈溢出和l束U程的生命来处理q些异常?/p>
从哪里发现默认行为?每个U程都属于一个由 ?Tiger 之前Q? 发生未捕L异常Ӟ默认行ؓ是将堆栈溢出打印输出到系l错误( 不用Q何参数运行该E序生成清?2 中的输出。尽它不是一个很长的堆栈跟踪Q但它是一个完整的堆栈跟踪?/p>
正如 Java q_的许多东西一P如果不喜Ƣ默认行为,您可以对其进行更攏V在 Java q_?Tiger 版以前的版本中,不能替代所有线E的默认行ؓQ但是可以创Z个新? q里创徏的定? 执行 清单 3 中的 发生q行时异常时Q可能要做许多工作来更改发生的问题。该代码的大部分都是 Logging HandlerQ但是,要执行更改,必ȝ? 使用 UncaughtExceptionHandler 的定制行?/span> 对于 TigerQ? 您可能没有注意到Q清?7 中的Ҏ与我们前面重写的 新的内部cd以帮助我们了解下列两ҎҎQƈ有助于我们在 W一Ҏ法是 听v来好像很单。ؓ了进行说明,清单 8 转换?清单 3 中的 该程序只是将 像添加未捕获的异常处理程序这L单库更改Q可以极大地增加原代码的可理解性。虽然在U程l别上Q新的库代码的功能与原来库代码的相同Q但新模型中的易用性和灉|性远q超Z代码调整ؓ更新的方式所需的时间。当Ӟ老方法仍然可以用,但最好将代码更新为最新的库功能?/p>
ThreadGroup
定制输出的老方法与通过提供自己?UncaughtExceptionHandler
定制输出的新Ҏ?java.lang.ThreadGroup
c表C的U程l。顾名思义Q线E组允许您将U程l合在一赗您可能是ؓ了方便而将U程l合Q例如,一个线E池中的所有线E都属于l?XQ而另一个池的所有线E则属于l?YQ或者是Z讉K控制而将U程q行l合。组 X 中的U程无权讉K或改变组 Y 中的U程Q除非它们都在同一U程l内Q或在一个子l内Q?ThreadGroup
cL供了一U处理未捕获异常的方法: ThreadGroup
?uncaughtException()
Ҏ。如果异怸?ThreadDeath
Q则线E的名称和堆栈回溯(stack backtraceQ发送到 System.err
。但?Tiger d了另一U方法: Thread.UncaughtExceptionHandler
接口。细?ThreadGroup
或安装该新接口的实现都允许您更改默认行ؓ。我们将?Tiger 之前和之后提供的Ҏ都进行研I?System.err
Q中Q如清单 1 中所C。不需要用Q何命令参数来启动E序?
清单 1. U程溢出CZ
public class SimpleDump {
public static void main(String args[]) {
System.out.println(args[0]);
}
}
清单 2. 默认U程溢出输出
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at SimpleDump.main(SimpleDump.java:3)
ThreadGroup
Qƈ更改在该l内创徏的Q何线E的默认行ؓ。您可以重写 uncaughtException(Thread t, Throwable e)
Ҏ来定制该行ؓ。然后,当发生未预料的运行时异常Ӟ该线E组内创建的MU程都将获得新的行ؓ。不q,最好是修复基础问题Q我提供一个简单的CZQ说明更攚w认行为所必需的步骤。清?3 展示了将执行代码攑օ新线E的调整q的试E序Q?
清单 3. 调整q的U程溢出CZ
public class WindowDump {
public static void main(String args[]) throws Exception {
ThreadGroup group = new LoggingThreadGroup("Logger");
new Thread(group, "myThread") {
public void run() {
System.out.println(1 / 0);
}
}.start();
}
}
LoggingThreadGroup
cL一个新的内容,清单 4 中显CZ它的定义。ؓ了进行说明,通过重写 uncaughtException()
Ҏ实现的特D行为将在一个弹出窗口中昄该异常,q项操作是在Ҏ Handler
的帮助下使用 Java Logging API 来完成的?
清单 4. LoggingThreadGroup 的定?/strong>
import java.util.logging.*;
public class LoggingThreadGroup extends ThreadGroup {
private static Logger logger;
public LoggingThreadGroup(String name) {
super(name);
}
public void uncaughtException(Thread t, Throwable e) {
// Initialize logger once
if (logger == null) {
logger = Logger.getLogger("example");
Handler handler = LoggingWindowHandler.getInstance();
logger.addHandler(handler);
}
logger.log(Level.WARNING, t.getName(), e);
}
}
Handler
的类型ؓ LoggingWindowHandler
Q该cd的定义在清单 5 中。处理程序用了一个支持类 LoggingWindow
Q该cd异常昄在屏q上?清单 6 中显CZ该类的定义?Handler
?public void publish(LogRecord record)
Ҏ实现了一些重要操作。其余操作大部分只与配置有关?
清单 5. LoggingWindowHandler 的定?/strong>
import java.util.logging.*;
public class LoggingWindowHandler extends Handler {
private static LoggingWindow window;
private static LoggingWindowHandler handler;
private LoggingWindowHandler() {
configure();
window = new LoggingWindow("Logging window...", 400, 200);
}
public static synchronized LoggingWindowHandler getInstance() {
if (handler == null) {
handler = new LoggingWindowHandler();
}
return handler;
}
/**
* Get any configuration properties set
*/
private void configure() {
LogManager manager = LogManager.getLogManager();
String className = getClass().getName();
String level = manager.getProperty(className + ".level");
setLevel((level == null) ? Level.INFO : Level.parse(level));
String filter = manager.getProperty(className + ".filter");
setFilter(makeFilter(filter));
String formatter =
manager.getProperty(className + ".formatter");
setFormatter(makeFormatter(formatter));
}
private Filter makeFilter(String name) {
Filter f = null;
try {
Class c = Class.forName(name);
f = (Filter)c.newInstance();
} catch (Exception e) {
if (name != null) {
System.err.println("Unable to load filter: " + name);
}
}
return f;
}
private Formatter makeFormatter(String name) {
Formatter f = null;
try {
Class c = Class.forName(name);
f = (Formatter)c.newInstance();
} catch (Exception e) {
f = new SimpleFormatter();
}
return f;
}
// Overridden abstract Handler methods
public void close() {
}
public void flush() {
}
/**
* If record is loggable, format it and add it to window
*/
public void publish(LogRecord record) {
String message = null;
if (isLoggable(record)) {
try {
message = getFormatter().format(record);
} catch (Exception e) {
reportError(null, e, ErrorManager.FORMAT_FAILURE);
return;
}
try {
window.addLogInfo(message);
} catch (Exception e) {
reportError(null, e, ErrorManager.WRITE_FAILURE);
}
}
}
}
清单 6. LoggingWindow 的定?/strong>
import java.awt.*;
import javax.swing.*;
public class LoggingWindow extends JFrame {
private JTextArea textArea;
public LoggingWindow(String title, final int width,
final int height) {
super(title);
EventQueue.invokeLater(new Runnable() {
public void run() {
setSize(width, height);
textArea = new JTextArea();
JScrollPane pane = new JScrollPane(textArea);
textArea.setEditable(false);
getContentPane().add(pane);
setVisible(true);
}
});
}
public void addLogInfo(final String data) {
EventQueue.invokeLater(new Runnable() {
public void run() {
textArea.append(data);
}
});
}
}
WindowDump
E序出现图 1 中的屏幕。因为没有从 Logger
中删除控制台处理E序Q所以堆栈溢Z出现在控制C?
?1. 记录的堆栈跟t?/strong>
ThreadGroup
Q重?uncaughtException()
Q然后在该线E组中执行您的线E。不q,让我们通过只安?Thread.UncaughtExceptionHandler
Q来看一?Tiger 的处理方式?
回页?/strong>
Thread
cd义中d了一个新的公共内部类 UncaughtExceptionHandler
Q更完整的名UCؓ Thread.UncaughtExceptionHandler
Q其他类讉K内部cL需要用完整名Uͼ。接口的定义是一个方法,如图 7 中所C:
清单 7. UncaughtExceptionHandler 的定?/strong>
public interface Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread, Throwable);
}
ThreadGroup
的方法相同。实际上Q现在由 ThreadGroup
cd现该接口?Thread
中用它们:
getUncaughtExceptionHandler()
?setUncaughtExceptionHandler()
?
getDefaultUncaughtExceptionHandler()
?setDefaultUncaughtExceptionHandler()
?getUncaughtExceptionHandler()
?setUncaughtExceptionHandler()
Q它们允许您为当前线E及其后代定制行为,从而允怺十或更多的线E拥有自q定制行ؓ。不q,您更可能使用W二Ҏ?getDefaultUncaughtExceptionHandler()
?setDefaultUncaughtExceptionHandler()
。如果用第二对Ҏ讄默认处理E序Q那么没有自q异常处理E序的所有线E都用默认处理程序?ThreadGroup
友好的程序,使用新的 UncaughtExceptionHandler
接口Q?
清单 8. UncaughtExceptionHandler CZ
public class HandlerDump {
public static void main(String args[]) throws Exception {
Thread.UncaughtExceptionHandler handler = new LoggingThreadGroup("Logger");
Thread.currentThread().setUncaughtExceptionHandler(handler);
System.out.println(1 / 0);
}
}
LoggingThreadGroup
重用?UncaughtExceptionHandler
Qƈ没有创徏新的处理E序实现。请注意Q与原来的代码相比,C码要z得多?
回页?/strong>
Thread
cM仅支持?Tiger d的未捕获异常处理E序Q它q支持?getAllStackTraces()
获得所有有效线E的堆栈跟踪Q或者支持?getStackTrace()
来只获得当前U程的堆栈跟t。这两种堆栈跟踪都返回类型ؓ java.lang.StackTraceElement
的对象, java.lang.StackTraceElement
?Java 1.4 q_中添加的一个类Q它可以让您生成自己的堆栈跟t。同ӞJava 5 q_新添加的功能是一个惟一U程标识W(可以使用 getId()
获得该标识符Q和一个新?Thread.State
c,以及与该cȝ关的 getThreadState()
Ҏ。最后一个线E更Ҏ一个状态枚举表Q该表是用来监视pȝ状态,而不是用来同步状态的?
回页?/strong>
public void run();
>>
而所有的具体U程都实现这个方法,所以这里就明确了一点,U程代码不能抛出Mchecked异常。所有的U程中的checked异常都只能被U程本n消化掉?) q样本n也是W合U程的设计理늚Q线E本w就是被看作独立的执行片断,它应该对自己负责Q所以由它来消化所有的checked异常是很正常的?
q样回{了g的第一个问题:checked异常一定要在线E内部消化?
但是Q线E代码中是可以抛出错?Error)和运行别异?RuntimeException)的。ErrorZ可以忽略Q因为通常Error是应该留lvm的,而RuntimeException是比较正常的,如果在运行过E中满了某U条件导致线E必M断,可以选择使用抛出q行U别异常来处理,如下Q?
<<
public void run() {
if (...) throw new RuntimeException();
}
>>
当线E代码抛行别异怹后,U程会中断?)q点java中解释得很清楚:
<< @see Thread
All threads that are not daemon threads have died, either by returning from the call to the run method or "by throwing an exception that propagates beyond the run method".
>>
但是对于invoke此线E的ȝE会产生什么媄响呢Q主U程不受q个影响Q不会处理这个RuntimeExceptionQ而且Ҏ不能catch到这个异常。会l箋执行自己的代? :)
所以得到结论:U程Ҏ的异常只能自己来处理?
关于最后一点,不相信的话大家可以做q么一个试验:
<<
public class TestThreadException extends Thread {
public void run() {
throw new RuntimeException();
}
public static void main(String[] args) throws InterruptedException {
try {
new TestThreadException().start();
} catch(RuntimeException ex) {
// 看看能不能到达这里? :)
}
Thread.sleep(1000);
// 看看能不能到达这里? :)
}
}
>>
C得在哪里看到的代码,可以处理到线E中抛出的RuntimeExceptionQ?
public class ApplicationLoader extends ThreadGroup
{
private ApplicationLoader()
{
super("ApplicationLoader");
}
public static void main(String[] args)
{
Runnable appStarter = new Runnable()
{
public void run()
{
//invoke your application (i.e.MySystem.main(args)
throw new NullPointerException(); //example, throw a runtime exception
}
};
new Thread(new ApplicationLoader(), appStarter).start();
}
//We overload this method from our parent
//ThreadGroup , which will make sure that it
//gets called when it needs to be. This is
//where the magic occurs.
public void uncaughtException(Thread thread, Throwable exception)
{
//Handle the error/exception.
//Typical operations might be displaying a
//useful dialog, writing to an event log, etc.
exception.printStackTrace();//example, print stack trace
}
}
呵呵QuncaughtException好像是唯一能够处理U程抛出的uncaught异常的入口。看来还是有l心人啊。确实如此,通过ThreadGroup的uncaughtExceptionҎq是有处理的Z。当U程抛出uncaughtException的时候,JVM会调用ThreadGroup的此Ҏ。默认的处理如下Q?
<<
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
e.printStackTrace(System.err);
}
}
>>
每个Thread都会有一个ThreadGroup对象Q可以通过Thread.getThreadGroup()Ҏ得到Q提供了上述默认的uncaught异常处理Ҏ?
上面没有提这点,因ؓ为在正常的情况下Q这个方法的处理情况已l够了。还是那个线E设计的理念Q?#8220;U程的问题应该线E自己本w来解决Q而不要委托到外部?#8221;通常情况下,外部不需要处理线E的异常。当然也有例外?)
Java 提供了两UException 的模式,一U是执行的时候所产生的Exception (Runtime Exception)Q另外一U则是受控制的Exception (Checked Exception)?/span>
所有的Checked Exception 均从java.lang.Exception l承而来Q而Runtime Exception 则承java.lang.RuntimeException 或java.lang.Error (实际上java.lang.RuntimeException 的上一层也是java.lang.ExceptionQ这说明作ؓexception两者ƈ没有本质的区别,只是java语言本n从功能考虑有所区分Q这才导致下面提到的不同??/span>
一个函数如果会抛出Checked Exception Q(q里包含两种情况Q一个是函数本n抛出Q另外一U是它调用的函数会抛出Checked Exception 但是它ƈ没有去catchq个exceptionQ,那在声明此函数的时候必L明throws XXXException()。而Runtime Exception不需要如此声明?/span>
逻辑上看QRuntime Exception 与Checked Exception 使用目的不一栗一般而言QChecked Exception 表示q个Exception 必须要被处理Q也是说程序设计者应该已l知道可能会收到某个Exception(因ؓ要try catch? Q所以程序设计者应该能也必(或者标明throws XXXException()l箋抛出去,或者try catch处理Q不然是~译不过的)针对q些不同的Checked Exception 做出不同的处理。而Runtime Exception 通常会暗C着E序上的错误Q这U错误会DE序设计者无法处理,而造成E序无法l箋执行下去Q可以try catch处理而避免程序挂掉,但是q常怼掩盖问题所在)?/span>
checked exception׃必须被处理,会给E序员带来额外的ȝQ试想一个函数aQ它会调用到b1Qb2...Qb9一?个函敎ͼq些函数每个都会抛出checked exceptionQ而a函数里面又没有办法处理这些exceptionQ那在声明a函数的时候就必须q写9个throw xxxExceptionQ够累的Q!然而这仅仅是问题的一个方面,所以下面这文章试图说服我们尽量用runtime exception替代checked exception(前面提到可以try catch处理runtime exceptionQ而避免程序挂掉,q也是这样做的一个前??/span>
q篇文章指出了Java中checked Exception的一些缺点,提出应该在程序设计中避免使用checked Exception,对于需要处理checked Exception的代码,可以使用ExceptionAdapterq个cdchecked Exceptionq行包装。这文章的概念和ExceptionAdapterq个cd源自Bruce Eckel的Does Java need Checked Exception?br />
Java?font face="Arial">Exception分ؓ两类Q一cLRuntimeException及其子类Q另外一cd?font face="Arial">checked Exception?font face="Arial">Java要求函数Ҏ有被catch处理掉的checked ExceptionQ需要将其写在函数的声明部分。然而,q一要求常常l程序员带来一些不必要的负担?/font>
Z避免在函数声明中?font face="Arial">throws部分Q在Java目里面常常可以看到以下代码用来‘吞掉’ExceptionQ?br />
q显然不是一个好的处?font face="Arial">Exception办法Q事实上Q?font face="Arial">catchq处理一?font face="Arial">Exception意味着让程序从发生的错?font face="Arial">(Exception)中恢复过来。从q种意义上说Q已上的代码只可能在一些很单的情况下工作而不带来问题?/font>
对于很多ExceptionQ往往没有d理它q让E序从错误中恢复出来的办法,q时唯一能做的事情可能就是在界面上显CZ些提CZ息给用户。这U情况下让程序抛出遇到的Exception是更为合理的做法。然而,q样做会使得一些函数的声明急剧膨胀。一个函数可能需要声明会抛出?font face="Arial">7?font face="Arial">8?font face="Arial">checked ExceptionQ而且每个调用它的函数也需要同L声明?/font>
比这更糟p的是,q有可能破坏c设计的open-close原则。简单来_open-close原则是指当扩展一个模块的时候,可以不媄响其现有?font face="Arial">client?font face="Arial">open-close原则是通过l承来实现的Q当l承一个类的时候,我们既扩展了q个c,也不会媄响原有的clientQ因为对q个cL有改动)?/font>
现在考虑下面q种情况Q有一个父c?font face="Arial">BaseQ?/font>
现在需要?font face="Arial">Baseq个cdƈ重蝲fooq个ҎQ在新的实现中,foo可能抛出ExceptionBQ?br />
然而,q样写在Java里面是不合法的,管Java不会抛出?font face="Arial">Exception看作函数特征的一部分Q但子类声明抛出?font face="Arial">Exception必须是父cȝ子集?br /> 可以?font face="Arial">BasecȝfooҎ中加入抛?font face="Arial">ExceptionB的声明,然而,q样q坏了open-close原则。而且Q有时我们没有办法去修改父类Q比如当重蝲一?font face="Arial">Jdk里的cȝ时候?/font>
另一个可能的做法是在Extend?font face="Arial">fooҎ?font face="Arial">catch?font face="Arial">ExceptionBQ然后构造一?font face="Arial">ExceptionAq抛出。这是个可行的办法但也只是一个权宜之计?/font>
如果使用RuntimeExceptionQ这些问题都不会存在。这说明checked Exceptionq不是一个很实用的概念,也意味着在程序设计的时候,我们应该让自qExceptioncȝ?font face="Arial">RuntimeException而不?font face="Arial">Exception。(q和JDK的徏议正好相反,但实践证明这样做代码的质量更好。)
对于那些需要处?font face="Arial">checked Exception的代码,可以利用一?font face="Arial">ExceptionAdapter的类?font face="Arial">checked Exception包装成一?font face="Arial">RuntimeException抛出?font face="Arial">ExceptionAdapter来自Bruce Eckel?font face="Arial">Does Java need Checked Exceptionq篇文章Q?br />
DBUtil是一个工L来关闭Connection.有必要的说的使用的finally的重要性是不管E序是否到异常Q它都会被执行。在上边的例子中Qfinally中关闭连接,如果在关闭连接的时候出现错误就抛出RuntimeException.
2Q?不要使用异常来控制流E(Never use exceptions for flow controlQ?br />
下边代码中,MaximumCountReachedException被用于控制流E:
上边的useExceptionsForFlowControl()用一个无限@环来增加count直到抛出异常Q这U做法ƈ没有说让代码不易读,但是它是E序执行效率降低?br />
CQ只在要会抛出异常的地方q行异常处理?br />
3Q?不要忽略异常
当有异常被抛出的时候,如果你不x复它Q那么你要毫不犹豫的其转换为unchecked exceptionQ而不是用一个空的catch块或者什么也不做来忽略它Q以至于从表面来看象是什么也没有发生一栗?br />
4Q?不要捕获层的Exception
unchecked exception都是RuntimeException的子c,RuntimeException又承Exception,因此Q如果单U的捕获Exception,那么你同样也捕获了RuntimeException,如下代码Q?br />
try{
..
}catch(Exception ex){
}
一旦你写出了上边的代码Q注意catch块是I的Q,它将忽略所有的异常Q包括unchecked exception.
5Q?Log exceptions just once
Logging the same exception stack trace more than once can confuse the programmer examining the stack trace about the original source of exception. So just log it once.
http://www.transwiki.org/wiki/index.php/OWL%E6%8C%87%E5%8D%97_%E6%8E%A8%E8%8D%90%E6%A0%87%E5%87%86-4#equivalentClass.2C_equivalentProperty Q本体介l)
http://imarine.blog.163.com/blog/static/5138018320071119110889/Q本体查询)
http://bbs.w3china.org/dispbbs.asp?boardID=2&ID=74918/ (本体查询Q?br />
-------------------------------------------------------
rdfs:subClassOf 描述
<owl:Class rdf:ID="Wine">
<rdfs:subClassOf rdf:resource="&food;PotableLiquid"/>
<rdfs:label xml:lang="en">wine</rdfs:label>
<rdfs:label xml:lang="fr">vin</rdfs:label>
</owl:Class>
Wine PotableLiquid
--------------------------------------------------------
ObjectProperty 描述 wine hasWinDescriptor WineDescriptor
<owl:ObjectProperty rdf:ID="hasWineDescriptor">
<rdfs:domain rdf:resource="#Wine" />
<rdfs:range rdf:resource="#WineDescriptor" />
</owl:ObjectProperty>
-------------------------------------------------------
DatatypeProperty 描述 VintageYear is 1998
<owl:DatatypeProperty rdf:ID="yearValue">
<rdfs:domain rdf:resource="#VintageYear" />
<rdfs:range rdf:resource="&xsd;positiveInteger" />
</owl:DatatypeProperty>
<VintageYear rdf:ID="Year1998">
<yearValue rdf:datatype="&xsd;positiveInteger">1998</yearValue>
</VintageYear>
<owl:ObjectProperty rdf:ID="hasVintageYear">
<rdf:type rdf:resource="&owl;FunctionalProperty" />
<rdfs:domain rdf:resource="#Vintage" />
<rdfs:range rdf:resource="#VintageYear" />
</owl:ObjectProperty>
Vintage has VintageYear that is 1998 ------ 葡萄酒的q䆾?998 ?1998的葡萄酒
--------------------------------------------------------
个体(individual) 描述
<owl:Class rdf:ID="WineGrape">
<rdfs:subClassOf rdf:resource="&food;Grape" />
</owl:Class>
<WineGrape rdf:ID="CabernetSauvignonGrape" />
CabernetSauvignonGrape is WineGrape ---- 赤霞珠葡萄树
----------------------属性特?-----------------------
TransitiveProperty 描述
SymmetricProperty 描述
<owl:Class rdf:ID="Region" />
<owl:ObjectProperty rdf:ID="locatedIn">
<rdf:type rdf:resource="&owl;TransitiveProperty" />
<rdfs:domain rdf:resource="
<rdfs:range rdf:resource="#Region" />
</owl:ObjectProperty>
<owl:ObjectProperty rdf:ID="adjacentRegion">
<rdf:type rdf:resource="&owl;SymmetricProperty" />
<rdfs:domain rdf:resource="#Region" />
<rdfs:range rdf:resource="#Region" />
</owl:ObjectProperty>
--------------------------------------------
FunctionalProperty 描述 一个给定的 Vintage个体只能使用hasVintageYear属性与单独一个年份相兌
<owl:Class rdf:ID="VintageYear" />
<owl:ObjectProperty rdf:ID="hasVintageYear">
<rdf:type rdf:resource="&owl;FunctionalProperty" />
<rdfs:domain rdf:resource="#Vintage" />
<rdfs:range rdf:resource="#VintageYear" />
</owl:ObjectProperty>
---------------------------------------------
inverseOf 描述 各种葡萄酒都有制造商
<owl:ObjectProperty rdf:ID="hasMaker">
<rdf:type rdf:resource="&owl;FunctionalProperty" />
</owl:ObjectProperty>
<owl:ObjectProperty rdf:ID="producesWine">
<owl:inverseOf rdf:resource="#hasMaker" />
</owl:ObjectProperty>
---------------------------------------------
InverseFunctionalProperty
<owl:ObjectProperty rdf:ID="hasMaker" />
<owl:ObjectProperty rdf:ID="producesWine">
<rdf:type rdf:resource="&owl;InverseFunctionalProperty" />
<owl:inverseOf rdf:resource="#hasMaker" />
</owl:ObjectProperty>
owl:InverseFunctional意味着属性的值域中的元素为定义域中的每个元素提供了一个唯一的标?/p>
---属性限?-----
-------------------------
allValuesFrom 描述 Wine的制造商必须是Winery?br />
owl:someValuesFrom替换owl:allValuesFromQ那意味着臛_有一个Winecd例的hasMaker属性是指向一个Winerycȝ个体的?/p>
<owl:Class rdf:ID="Wine">
<rdfs:subClassOf rdf:resource="&food;PotableLiquid" />
...
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource="#hasMaker" />
<owl:allValuesFrom rdf:resource="#Winery" />
</owl:Restriction>
</rdfs:subClassOf>
...
</owl:Class>
-------------------------------------------------------
owl:cardinality 描述 允许对一个关pM的元素数目作出精的限制
<owl:Class rdf:ID="Vintage">
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource="#hasVintageYear"/>
<owl:cardinality rdf:datatype="&xsd;nonNegativeInteger">1</owl:cardinality>
</owl:Restriction>
</rdfs:subClassOf>
</owl:Class>
每瓶葡萄酒只有一个年?/p>
-------------------------------------------------------
hasValue 描述 一个个体只要至有“一?#8221;属性值等于hasValue的资源,q一个体是该类的成员?/p>
<owl:Class rdf:ID="Burgundy">
...
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource="#hasSugar" />
<owl:hasValue rdf:resource="#Dry" />
</owl:Restriction>
</rdfs:subClassOf>
</owl:Class>
所有的Burgundy酒都是干(dry)的酒。也卻I它们的hasSugar属性必至有一个是值等于DryQ干的)
------------------------------------------------------
本体映射
cd属性之间的{h关系Q-equivalentClass, equivalentProperty
<owl:Class rdf:ID="TexasThings">
<owl:equivalentClass>
<owl:Restriction>
<owl:onProperty rdf:resource="#locatedIn" />
<owl:someValuesFrom rdf:resource="#TexasRegion" />
</owl:Restriction>
</owl:equivalentClass>
</owl:Class>
TexasThings指的是那些恰好位于TexasRegion的事物。用owl:equivalentClass 和用rdfs:subClassOf 的不同就像必要条件和充要条g的不同一栗如果是使用subClassOf的话Q位于TexasRegion的事物不一定是TexasThings。但是,如果使用owl:equivalentClassQ位于TexasRegion的事物一定属于TexasThingscR?/p>
------------------------------------------------------
个体间的同一?QsameAs
<Wine rdf:ID="MikesFavoriteWine>
<owl:sameAs rdf:resource="#StGenevieveTexasWhite" />
</Wine>
修饰Q或引用Q两个类用sameAsq是用equivalentClass效果是不同的。用sameAs的时候,把一个类解释Z个个体,像在OWL Full中一Pq有利于Ҏ体进行分cR?/p>
-----------------------------------------------------
不同的个?br />
------------------------------------------------------
differentFrom
<WineSugar rdf:ID="Dry" />
<WineSugar rdf:ID="Sweet">
<owl:differentFrom rdf:resource="#Dry"/>
</WineSugar>
<WineSugar rdf:ID="OffDry">
<owl:differentFrom rdf:resource="#Dry"/>
<owl:differentFrom rdf:resource="#Sweet"/>
</WineSugar>
---------------------------------------------------
AllDifferent
<owl:AllDifferent>
<owl:distinctMembers rdf:parseType="Collection">
<vin:WineColor rdf:about="#Red" />
<vin:WineColor rdf:about="#White" />
<vin:WineColor rdf:about="#Rose" />
</owl:distinctMembers>
</owl:AllDifferent>
owl:distinctMembers属性声明只能和owl:AllDifferent属性声明一L合用?/p>
-----------------------------------------------------
intersectionOf
<owl:Class rdf:ID="WhiteWine">
<owl:intersectionOf rdf:parseType="Collection">
<owl:Class rdf:about="#Wine" />
<owl:Restriction>
<owl:onProperty rdf:resource="#hasColor" />
<owl:hasValue rdf:resource="#White" />
</owl:Restriction>
</owl:intersectionOf>
</owl:Class>
WhiteWine恰好是类Wine与所有颜色是白色的事物的集合的交?/p>
-----------------------------------------------------
unionOf
<owl:Class rdf:ID="Fruit">
<owl:unionOf rdf:parseType="Collection">
<owl:Class rdf:about="#SweetFruit" />
<owl:Class rdf:about="#NonSweetFruit" />
</owl:unionOf>
</owl:Class>
------------------------------------------------------
complementOf 从某个论?domain of discourse)选出不属于某个类的所有个?/p>
<owl:Class rdf:ID="NonFrenchWine">
<owl:intersectionOf rdf:parseType="Collection">
<owl:Class rdf:about="#Wine"/>
<owl:Class>
<owl:complementOf>
<owl:Restriction>
<owl:onProperty rdf:resource="#locatedIn" />
<owl:hasValue rdf:resource="#FrenchRegion" />
</owl:Restriction>
</owl:complementOf>
</owl:Class>
</owl:intersectionOf>
</owl:Class>
-----------------------------------------------------------
oneOf 枚D
<owl:Class rdf:ID="WineColor">
<rdfs:subClassOf rdf:resource="#WineDescriptor"/>
<owl:oneOf rdf:parseType="Collection">
<owl:Thing rdf:about="#White"/>
<owl:Thing rdf:about="#Rose"/>
<owl:Thing rdf:about="#Red"/>
</owl:oneOf>
</owl:Class>
有效的个体声?/p>
-----------------------------------------------------------
disjointWith 不相交类 保证了属于某一个类的个体不能同时又是另一个指定类的实?/p>
<owl:Class rdf:ID="Pasta">
<rdfs:subClassOf rdf:resource="#EdibleThing"/>
<owl:disjointWith rdf:resource="#Meat"/>
<owl:disjointWith rdf:resource="#Fowl"/>
<owl:disjointWith rdf:resource="#Seafood"/>
<owl:disjointWith rdf:resource="#Dessert"/>
<owl:disjointWith rdf:resource="#Fruit"/>
</owl:Class>
Pasta与其它所有类是不怺的。例如,它ƈ没有保证Meat和Fruit是不怺?/p>
Person.java
class Person
{
public String name = "not know";//4
public int age = -1 ;//5
public Person()
{
}
public Person(String name , int age)//3
{
this.name = name ;//6
this.age = age;//7
}
public void showInfo()
{
System.out.println("Name is :"+name+" Age is :"+age);
}
}
class Student extends Person
{
public String school = "not konwn";//8
public Student()
{
super();
}
public Student (String name ,int age, String school) //1
{
super(name,age); //2
this.school = school;//9
}
public void showInfo()
{
super.showInfo();
System.out.println("School is :"+school);
}
}
AllTest.java
class AllTest
{
public static void main(String[]args)
{
Student stA = new Student("wanghao",20,"qinghuadaxue"); //0
}
}
其语句的执行序是怎样的呢Q?/span>
java中,在?/span>new操作W创Z个类的实例对象的时候,开始分配空间ƈ成员变量初始化?/span>默认?/span>数?/span>Q注意这里ƈ不是指将变量初始化ؓ在变量定义处的初始|?strong>是给整Ş赋?/span>0Q给字符串赋?/span>null q一点于C++不同Q(student.name = null , student.age = 0 Q?/span>
然后在进入类的构造函数?/span>
在构造函数里面,首先要检查是否有this或?/span>super调用Q?/span>this调用是完成本cLw的构造函C间的调用Q?/span>super调用是完成对父类的调用?strong>二者只能出C个,q且只能作ؓ构造函数的W一句出现?/span>在调?/span>this?/span>super的时候实现程序的跌{Q{而执行被调用?/span>this构造函数或?/span>super构造函数?/span>
?/span>this?/span>super执行完毕Q?strong>E序转而执行在cd义的时候进行的变量初始化工?/span>?/span>
q个执行完毕Q才是构造函C剩下的代码的执行?/span>
执行序已经用绿色标出?/span>
Order of initialization
Within a class, the order of initialization is determined by the order that the variables are defined within the class. The variable definitions may be scattered throughout and in between method definitions, but the variables are initialized before any methods can be called—even the constructor. For example: Feedback
//: c04:OrderOfInitialization.java
// Demonstrates initialization order.
import com.bruceeckel.simpletest.*;
// When the constructor is called to create a
// Tag object, you'll see a message:
class Tag {
Tag(int marker) {
System.out.println("Tag(" + marker + ")");
}
}
class Card {
Tag t1 = new Tag(1); // Before constructor
Card() {
// Indicate we're in the constructor:
System.out.println("Card()");
t3 = new Tag(33); // Reinitialize t3
}
Tag t2 = new Tag(2); // After constructor
void f() {
System.out.println("f()");
}
Tag t3 = new Tag(3); // At end
}
public class OrderOfInitialization {
static Test monitor = new Test();
public static void main(String[] args) {
Card t = new Card();
t.f(); // Shows that construction is done
monitor.expect(new String[] {
"Tag(1)",
"Tag(2)",
"Tag(3)",
"Card()",
"Tag(33)",
"f()"
});
}
} ///:~
//: c04:StaticInitialization.java
// Specifying initial values in a class definition.
class Bowl {
Bowl(int marker) {
System.out.println("Bowl(" + marker + ")");
}
void f(int marker) {
System.out.println("f(" + marker + ")");
}
}
class Table {
static Bowl b1 = new Bowl(1);
Table() {
System.out.println("Table()");
b2.f(1);
}
void f2(int marker) {
System.out.println("f2(" + marker + ")");
}
static Bowl b2 = new Bowl(2);
}
class Cupboard {
Bowl b3 = new Bowl(3);
static Bowl b4 = new Bowl(4);
Cupboard() {
System.out.println("Cupboard()");
b4.f(2);
}
void f3(int marker) {
System.out.println("f3(" + marker + ")");
}
static Bowl b5 = new Bowl(5);
}
public class StaticInitialization {
static Test monitor = new Test();
public static void main(String[] args) {
System.out.println("Creating new Cupboard() in main");
new Cupboard();
System.out.println("Creating new Cupboard() in main");
new Cupboard();
t2.f2(1);
t3.f3(1);
monitor.expect(new String[] {
"Bowl(1)",
"Bowl(2)",
"Table()",
"f(1)",
"Bowl(4)",
"Bowl(5)",
"Bowl(3)",
"Cupboard()",
"f(2)",
"Creating new Cupboard() in main",
"Bowl(3)",
"Cupboard()",
"f(2)",
"Creating new Cupboard() in main",
"Bowl(3)",
"Cupboard()",
"f(2)",
"f2(1)",
"f3(1)"
});
}
static Table t2 = new Table();
static Cupboard t3 = new Cupboard();
} ///:~
l承情况下的初始?br />
了解一下包括承在内的初始化的q程是非常有益的,q样p有个?br />
体的了解。看看下面这D代码:
//: c06:Beetle.java
// The full process of initialization.
class Insect {
protected static Test monitor = new Test();
private int i = 9;
protected int j;
Insect() {
System.out.println("i = " + i + ", j = " + j);
j = 39;
}
private static int x1 = print("static Insect.x1 initialized");
static int print(String s) {
System.out.println(s);
return 47;
}
}
public class Beetle extends Insect {
private int k = print("Beetle.k initialized");
public Beetle() {
System.out.println("k = " + k);
System.out.println("j = " + j);
}
private static int x2 = print("static Beetle.x2 initialized");
public static void main(String[] args) {
System.out.println("Beetle constructor");
Beetle b = new Beetle();
monitor.expect(new String[] {
"static Insect.x1 initialized",
"static Beetle.x2 initialized",
"Beetle constructor",
"i = 9, j = 0",
"Beetle.k initialized",
"k = 47",
"j = 39"
});
}
} ///:~
你寻扄~译?/span>Beetle cȝ代码(也就?/span>Beetle.class 文g)。在装蝲的过E中Q装载器注意到它有一个基c?/span>(也就?/span>extends 所要表C的意?/span>)Q于是它再装载基cR不你创不创徏基类对象Q这个过EM发生?/span>(试试看,把创建对象的那句注释掉,看看会有什么结果?/span>)如果基类q有基类Q那么这W二个基cM会被装蝲Q以此类?span style="color: blue">?strong>下一步,它会执行“根基c?/strong>(root bas e class)”(q里是Insect)?/span>static 初始化,然后是下一个派生类?/span>static 初始化,以此cL。这个顺序非帔R要,因ؓzcȝ“静态初始化(卛_面讲?/span>static 初始?/span>)”有可能要依赖基类成员的正初始化?/span>
现在所有必要的c都已经装蝲l束Q可以创建对象了?/span>首先Q对象里的所有的primitive 都会被设成它们的~省|?/span>reference 也会被设?/span>null——这个过E是一瞬间完成的,对象的内存会被统一地设|成“两进制的?/span>(binary zero)”?strong>如果有对成员变量赋初|则对成员变量q行赋|然后调用基类的构造函数。调用是自动发生的,但是你可以?/span>super 来指定调用哪个构造函?/span>(也就Beetle( )构造函数所做的W一件事)。基cȝ构造过E以及构造顺序,同派生类的相同。基cL造函数运行完毕之后,会按照各个变量的字面序q行初始化。最后会执行构造函数的其余部分?/span>
q回Q?
一个字W串Q内容与此字W串相同Q但它保证来自字W串池中?
=======================================================================
字符串字面池指的是常量池.
字符串对象的创徏方式有两U?/p>
如下:
String s1 = new String(""); //W一U?/p>
String s2 = ""; //W二U?/p>
W一U始l不会入池的.
W二U要看情况而定({号双如果是常量则入池,非常量则不入?
?
String s3 = "a" + "b"; //"a"是常?"b"是常?帔R+帔R=帔R,所以会入池.
String s4 = s1 + "b"; //s1是变?"b"是常?变量+帔R!=帔R,所以不会入?
//那引用s4所指的对象在哪里创??????
一旦入池的?׃先查找池中有无此对象.如果有此对象,则让对象引用指向此对?如果无此对象,则先创徏此对?再让对象引用指向此对?
?
String s5 = "abc"; //先在池中查找有无"abc"对象,如果?则让s5指向此对?如果池中?abc"对象,则在池中创徏一?abc"对象,然后让s5指向该对?补充一下:
看了字节码后Q发?br />
String str ="a"+"b";
完全{同?br />
String str="ab";
-----------------------------------------------------------------------------------------------------------------------------
Java虚拟机有一个字W串池,保存着几乎所有的字符串常量。字W串表达式L指向字符串池中的一个对象?br />
public class Test...{
public static void main(String[] args)...{
String s1=new String("abc");
String s2="abc";//攑օString池里
String s3=new String("abc");
System.out.println(s1==s2);//false
System.out.println(s1==s3);//false
System.out.println(s3==s2);//false
System.out.println(s1==s1.intern());//s1.intern()到String池里找,而s1是在堆中所以返回false
System.out.println(s2==s2.intern());//true
System.out.println(s1.intern()==s3.intern());//两个字符串同时到String池里查找Q返回true
//以下三个都放到String?br />
String hello="hello";
String hel="hel";
String lo="lo";
System.out.println(hello=="hel"+"lo");//字符串相加以后,会到String池里找,有不产生Q所以返回true
System.out.println(hello=="hello");//直接到String池里找,q回true
System.out.println(hello=="hel"+lo);//字符串加一个引用,生一个新的对象,所以返回false
System.out.println(hello==(hel+lo));//cM上面Q返回false
System.out.println(hello==(hel+lo).intern());//产生新的对象Q但是有intern()ҎQ将到String池中找,q回true
}
}