java 终极超类,Java问答:终极父类(3),java问答
Java问答:终极父类(3),java问答Java问答:终极父类(上)
Java问答:终极父类(下)
Java问答:终极父类(2)—上篇
Java问答:终极父类(2)—下篇
在之前关于 Object 的系列文章中,我们探讨了 finalize()、getClass()和hashCode()方法。在这篇文章中,我们将在Java8环境中继续讨论 toString() 方法,等待/唤醒方法和 Object 中的接口。
字符串形式的表现
Q1:toString() 方法实现了什么功能?
A1:toString() 方法将根据调用它的对象返回其对象的字符串形式,通常用于debug。
Q2:当 toString() 方法没有被覆盖的时候,返回的字符串通常是什么样子的?
A2:当 toString() 没有被覆盖的时候,返回的字符串格式是 类名@哈希值,哈希值是十六进制的。举例说,假设有一个 Employee 类,toString() 方法返回的结果可能是 Empoyee@1c7b0f4d。
Q3:能提供一个正确覆盖 toString() 方法的例子吗?
A3:见代码清单1:
public class Employee
{
private String name;
private int age;
public Employee(String name, int age)
{
this.name = name;
this.age = age;
}
@Override
public String toString()
{
return name + ": " + age;
}
}
代码清单1:返回一个非默认的字符串形式
代码清单1声明了 Employee 类,被私有修饰符修饰的 name 和 age 变量,构造器将其初始化。该类覆盖了 toString() 方法,并返回一个包含对象值和一个冒号的 String 对象。
字符串和 StringBuilder
当编译器遇到 name + ": " + age 的表达时,会生成一个 java.lang.StringBuilder 对象,并调用 append() 方法来对字符串添加变量值和分隔符。最后调用 toString() 方法返回一个包含各个元素的字符串对象。
Q4:如何得到字符串的表达形式?
A4:根据对象的引用,调用引用的 toString() 。例如,假设 emp 包含了一个 Employee 引用,调用 emp.toString() 就会得到这个对象的字符串形式。
Q5:System.out.println(o.toString()); 和 System.out.println(o) 的区别是什么?
A5:System.out.println(o.toString()); 和 System.out.println(o) 两者的输出结果中都包含了对象的字符串形式。区别是,System.out.println(o.toString()); 直接调用toString() 方法,而System.out.println(o) 则是隐式调用了 toString()。
等待和唤醒
Q6:wait(),notify() 和 notifyAll() 是用来干什么的?
A6:wait(),notify() 和 notifyAll() 可以让线程协调完成一项任务。例如,一个线程生产,另一个线程消费。生产线程不能在前一产品被消费之前运行,而应该等待前一个被生产出来的产品被消费之后才被唤醒,进行生产。同理,消费线程也不能在生产线程之前运行,即不能消费不存在的产品。所以,应该等待生产线程执行一个之后才执行。利用这些方法,就可以实现这些线程之间的协调。从本质上说,一个线程等待某种状态(例如一个产品被生产),另一个线程正在执行,知道产生了某种状态(例如生产了一个产品)。
Q7:不同的 wait() 方法之间有什么区别?
A7:没有参数的 wait() 方法被调用之后,线程就会一直处于睡眠状态,直到本对象(就是 wait() 被调用的那个对象)调用 notify() 或 notifyAll() 方法。相应的wait(long timeout)和wait(long timeout, int nanos)方法中,当等待时间结束或者被唤醒时(无论哪一个先发生)将会结束等待。
Q8:notify() 和 notifyAll() 方法有什么区别?
A8:notify() 方法随机唤醒一个等待的线程,而 notifyAll() 方法将唤醒所有在等待的线程。
Q9:线程被唤醒之后会发生什么?
A9:当一个线程被唤醒之后,除非本对象(调用 notify() 或 notifyAll() 的对象)的同步锁被释放,否则不会立即执行。唤醒的线程会按照规则和其他线程竞争同步锁,得到锁的线程将执行。所以notifyAll()方法执行之后,可能会有一个线程立即运行,也可能所有的线程都没运行。
Q10:为什么在使用等待、唤醒方法时,要放在同步代码中?
A10::将等待和唤醒方法放在同步代码中是非常必要的,这样做是为了避免竞争条件。鉴于要等待的线程通常在调用wait()之前会确认一种情况存在与否(通常是检查某一变量的值),而另一线程在调用notify()`之前通常会设置某种情况(通常是通过设置一个变量的值)。以下这种情况引发了竞争条件:
线程一检查了情况和变量,发现需要等待。
线程二设置了变量。
线程二调用了notify()。此时,线程一还没有等待,所以这次调用什么用都没有。
线程一调用了wait()。这下它永远不会被唤醒了。
Q11:如果在同步代码之外使用这些方法会怎么样呢?
A11:如果在同步代码之外使用了这些情况,就会抛出java.lang.IllegalMonitorStateException异常。
Q12:如果在同步代码中调用这些方法呢?
A12:当 wait() 方法在同步代码中被调用时,会根据同步代码中方法的优先级先后执行。在wait()方法返回值之前,该同步代码一直持有锁,这样就不会出现竞争条件了。在wait()方法可以接受唤醒之前,锁一直不会释放。
Q13:为什么要把wait()调用放在while循环中,而不是if判断中呢?
A13:为了防止假唤醒,可以在 stackoverflow上了解有关这类现象的更多信息——假唤醒真的会发生吗?。
Q14:能提供一个使用等待与唤醒方法的范例吗?
A14:见代码清单2:
public class WaitNotifyDemo
{
public static void main(String[] args)
{
class Shared
{
private String msg;
synchronized void send(String msg)
{
while (this.msg != null)
try
{
wait();
}
catch (InterruptedException ie)
{
}
this.msg = msg;
notify();
}
synchronized String receive()
{
while (msg == null)
try
{
wait();
}
catch (InterruptedException ie)
{
}
String temp = msg;
msg = null;
notify();
return temp;
}
}
final Shared shared = new Shared();
Runnable rsender;
rsender = new Runnable()
{
@Override
public void run()
{
for (int i = 0; i < 10; i++)
{
shared.send("A"+i);
try
{
Thread.sleep((int)(Math.random()*200));
}
catch (InterruptedException ie)
{
}
}
shared.send("done");
}
};
Thread sender = new Thread(rsender);
Runnable rreceiver;
rreceiver = new Runnable()
{
@Override
public void run()
{
String msg;
while (!(msg = shared.receive()).equals("done"))
{
System.out.println(msg);
try
{
Thread.sleep((int)(Math.random()*200));
}
catch (InterruptedException ie)
{
}
}
}
};
Thread receiver = new Thread(rreceiver);
sender.start();
receiver.start();
}
}
代码清单2:发送与接收信息
代码清单2声明了一个WaitNotifyDemo类。其中,main()方法有一对发送和接收信息的线程。
main()方法首先声明了Shard本地类,包含接收和发送信息的任务。Share声明了一个String类型的smg私有成员变量来存储要发送的信息,同时声明了同步的 send()和receive()方法来执行接收和发送动作。
发送线程调用的是send()。因为上一次调用send()的信息可能还没有被接收到,所以这个方法首先要通过计算this.msg != null的值来判断信息发送状态。如果返回值为true,那么信息处于被等待发送的状态,就会调用 wait() 。一旦信息被接收到,接受的线程就会给msg赋值为null并存储新信息,调用notify()唤醒等待的线程。
接收线程调用的是receive()因为可能没有信息处于被接收状态,这个方法首先会通过计算mas == null的值来验证信息有没有等待被接收的状态。如果表达式返回值为true,就表示没有信息等待被接收,此线程就要调用 wait() 方法。如果有信息发送,发送线程就会给 msg 分配值并且调用notify()唤醒接收线程。
编译(javac WaitNotifyDemo.java)并运行(java WaitNotifyDemo)源代码,将会看到以下输出结果:
A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
Q15:我想更加深入的学习等待和唤醒的机制,能提供一些资源吗?
A15:可以在artima参考Bill Venners的书《Inside the Java Virtual Machine(深入理解 Java 虚拟机)》中第20章 wait().artima.com/insidejvm/ed2/threadsynch.html">Chapter 20: Thread Synchronization。
Object接口和Java8
Q16:在第一部分中提到过接口是不继承Object的。然而,我发现有些接口中声明了Object中的方法。比如java.util.Comparator接口有boolean.equals(Object.obj)。为什么呢?
A16:Java语言规范的9.6.3.4部分中清楚说明了,接口有相当于 Object 中成员那样的公共抽象成员。此外,如果接口中声明了Object中的成员函数(例如,声明的函数相当于覆盖 Object中的public方法),则认为是接口覆盖了他们,可以用 @Override注释。
为什么要在接口中声明非final的public Object方法(可能还带有 @Override)呢?举例来说,Comparator接口中就有boolean equals(Object obj)声明,这个方法在接口中声明就是为了此接口的特殊情况。
此外,这个方法只有在传入的类是一个比较规则相同的比较器的时候,才能返回 true。
因为这种情况是可选的,所以并不强制实现 Comparator。这取决于有没有equals,只有在遇到一个比较规则相同的比较器的时候才返回true的需求。尽管类并不要求覆盖equals,但是文档中却支持这样做来提高性能。
注意,不覆盖 Object.equals(Object)是安全的。但是,覆盖这个方发可能在一些情况下提高性能,比如让程序判断两个不同的比较器是不是用的相同规则。
Q17:哪一个equals()方法被覆盖了?是Object中的,还是接口中的?
A17:更早的文档中说,被覆盖的方法是在Object中的。
Q18:Java 8支持接口中的默认方法。可以在接口中默认实现Employee方法或者Object中的其他方法吗?
A18:不可以。Object中的任何public的非final方法都是不允许在接口中默认实现的。这个限制的基本原理在Brian Goetz的允许默认方法覆盖Object中的方法一文中有说明。
Q19:能提供更多关于接口中 Object 方法的学习资源吗?
A19:可以参考这篇接口继承了Object类吗?。
原文链接: javaworld 翻译: Wld5.com - 赖 信涛
译文链接: http://www.wld5.com/13256.html
[ 转载请保留原文出处、译者和译文链接。]
java 终极超类,Java问答:终极父类(3),java问答相关推荐
- 115个Java面试题和答案——终极列表(上)
转载自 115个Java面试题和答案--终极列表(上) 本文我们将要讨论Java面试中的各种不同类型的面试题,它们可以让雇主测试应聘者的Java和通用的面向对象编程的能力.下面的章节分为上下两篇,第 ...
- 115个Java面试题和答案——终极列表(下)
转载自 115个Java面试题和答案--终极列表(下) 第一篇讨论了面向对象编程和它的特点,关于Java和它的功能的常见问题,Java的集合类,垃圾收集器,本章主要讨论异常处理,Java小应用程序 ...
- Github下载热榜,阿里最新出品Java面试核心讲(终极版)
程序员面试背八股,可以说是现在互联网开发岗招聘不可逆的形式了,其中最卷的当属Java!(网上动不动就是成千上百道的面试题总结)你要是都能啃下来,平时技术不是太差的话,面试基本上问题就不会太大. 这时候 ...
- 115 个 Java 面试题和答案——终极重点(下)
题目:115 个 Java 面试题和答案--终极(下) 第一篇讨论了面向对象编程和它的特点,关于 Java 和它的功能的常见问题,Java 的集合类,垃圾收集器,本章主要讨论异常处理,Java 小应用 ...
- Java 8的新特性—终极版
前言: Java 8 已经发布很久了,很多报道表明Java 8 是一次重大的版本升级.在Java Code Geeks上已经有很多介绍Java 8新特性的文章,例如Playing with Java ...
- 115个Java面试题和答案——终极列表
开始! 目录 面向对象编程(OOP) 常见的Java问题 Java线程 Java集合类 垃圾收集器 面向对象编程(OOP) Java是一个支持并发.基于类和面向对象的计算机编程语言.下面列出了面向对象 ...
- 【三万粉丝终极福利】Python、C、Java三大语言学习路线和资源整理
大家好,我是辣条. 今天给大家带来三万粉丝三大语言学习路线和资源整理,收藏就对了. 目录 C语言 学习路线 学习书籍 学习视频 资源推荐 Java语言 学习路线 学习书籍 学习视频 资源推荐 Pyth ...
- 关于Spring的69个面试问答和Top25个问答--终极列表,以及Spring相关知识
Spring 框架越来越流行,很多大型系统用到,了解Spring的面试题有助简要短时间于了解对应的知识, 关于Spring的69个面试问答--终极列表 http://www.importnew.com ...
- 转:Java中子类是否可以继承父类的static变量和方法而呈现多态特性
原文地址:Java中子类是否可以继承父类的static变量和方法而呈现多态特性 静态方法 通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法,关于static方法,声明 ...
最新文章
- css控制非固定文本自动换行
- python3.7安装turtle步骤-Python3安装turtle问题
- ASP.NET 定时执行任务(定时器)
- cocos2dx集成友盟社会化分享图片崩溃问题
- 關於@Override
- 操作系统 | 用户态和内核态的切换(中断、系统调用与过程(库函数)调用)
- 什么是 NoSQL 数据库、NoSQL 与 SQL 的区别
- laravel 向模板中添加公共变量
- modem(2)---Android modem log查看
- 使用 android adb命令 录像 screenrecord 和 截屏 screencap
- 概率图模型和马尔可夫模型
- 激光导航AGV为何如此受企业青睐?
- 女孩假扮大学生跪地乞讨月入万元
- word2vec:基于层级 softmax 和负采样的 Skip-Gram
- Ai-WB1系列驱动4.0寸电阻触摸屏运行LVGL v8.3
- 新旧电脑安装win11系统【超简单教程】
- Oracle读书列表
- 房产行业php_phpwind房产系统打响社区垂直行业应用
- 台式电脑计算机硬盘清理,台式机的硬盘不够用怎么办 解决台式机电脑硬盘
- java提示程序包不存在,解决:Error:java xxxx 程序包不存在
热门文章
- git for c#, clone方法
- 浅谈Android系统开发中LOG的使用【转】
- 2010.2--netscreen ssg 140 恢复出厂设置的方法
- sqlmap绕过d盾_WEBSHELL免杀绕过WAF思路amp;方法(一)
- 兵团教师计算机水平考试免考条件,兵团职称计算机考试政策.doc
- android listview edittext 焦点冲突,Android开发之ListView+EditText-要命的焦点和软键盘问题解决办法...
- 简单介绍oracle重置序列的方法
- Python中scrapy下载保存图片
- 计算机ppt继续教育,泰州市专业技术人员继续教育公需科目PPT2010试卷及答案
- java别踩白块_java别踩白块(基础功能)