@HUST-SuWB
2015-02-01T08:39:01.000000Z
字数 16819
阅读 364
项目实战
我们以Java的三大基本特性为角度展开
封装、继承、多态
封装:
封装是把过程和数据包围起来,对数据的访问只能通过已定义的接口。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。封装主要实现了隐藏细节,对用户提供访问接口,无需关心方法的具体实现。
Java的权限控制等级由大到小依次为:public、protected、(default)、private,对应的访问权限分别为所有、本包内和子类、本包、自己。
继承:
继承是面向对象最显著的一个特性。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。Java继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。关键字:extends。
多态:
多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。
多态有两种表现形式:重载和重写。
首先我们来讲讲:重载(Overloading)
(1) 方法重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型。
重载Overloading是一个类中多态性的一种表现。
(2) Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。
调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性。
(3) 重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准。
然后我们再来谈谈 重写(Overriding)
(1) 父类与子类之间的多态性,对父类的函数进行重新定义。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。
但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。
方法重写又称方法覆盖。
(2)若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。
如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
(3)子类函数的访问修饰权限不能少于父类的;
首先解释一下heap(堆)和stack(栈)的概念。
Heap和stack都属于内存中的两块区域,其中,stack的存取速度更高一些。
Heap:所有的对象(实例变量存在所属的对象中,所以也存放在heap上)。
Stack:方法调用和局部变量。
其中,heap中的对象一旦没有了引用,则会被垃圾回收器回收。
我们需要明确一个概念,那就是每当我们在写如下语句的时候:A a = new A();我们一共做了三件事情:申明了一个a;新建了一个A对象并在heap上为它开辟了一部分空间;把a指向了A对象。
所以,一个简单的例子:
Book b = new Book();
Book c = new Book();
b = c;//第一个Book对象被回收
c= null;
b= null;//第二个Book对象也被回收
Java API中所用的集合类,都是实现了Collection接口,他的一个类继承结构如下:
(最下面一层之外全是借口)
Collection<--List<--Vector
Collection<--List<--ArrayList
Collection<--List<--LinkedList
Collection<--Set<--HashSet
Collection<--Set<--HashSet<--LinkedHashSet
Collection<--Set<--SortedSet<--TreeSet
Map<--HashMap
Map<--LinkedHashMap
Map<--Hashtable
Map<--SortedMap <--TreeMap
简单讲解一下他们的区别:
Set | Map | List |
---|---|---|
注重独一无二的性质,不允许重复,它知道某物是否已经存在与集合中 | 使用成对的键值和数据值,key不能重复 | 知道某物在系列集合中的位置,可以有多个元素引用相同的对象 |
推荐资料:http://www.cnblogs.com/eflylab/archive/2007/01/19/625086.html
在写代码的时候经常会碰到对日期的处理,而DateFormat、NumberFormat、Calendar 均是抽象类,不能进行实例化,只能通过getInstance()方法获得实例对象。DateFormat a = DateFormat.getInstance();
NumberFormat b = NumberFormat.getInstance();
Calendar c = Calendar.getInstance();
下面我介绍几种主要的方式
Calendar calendar = Calendar.getInstance();// 取当前日期
int year =calendar.get(Calendar.YEAR);
int month=calendar.get(Calendar.MONTH)+1;
int day =calendar.get(Calendar.DAY_OF_MONTH);
int hour =calendar.get(Calendar.HOUR_OF_DAY);
int minute =calendar.get(Calendar.MINUTE);
int second =calendar.get(Calendar.SECOND);
java.util.Date today=new java.util.Date();
java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd");
String now = dateFormat.format(today);
Date date = new Date(); //取得当前日期,精确到毫秒
DateFormat dateformat1 = DateFormat.getDateInstance(0);
String datestr1 = dateformat1.format(date);
// datestr1 = 2014年5月7日 星期三
DateFormat dateformat2 = DateFormat.getDateInstance(1);
String datestr2 = dateformat2.format(date);
// datestr2 = 2014年5月7日
DateFormat dateformat3 = DateFormat.getDateInstance(2);
String datestr3 = dateformat3.format(date);
// datestr3 = 2014-5-7
DateFormat dateformat4 = DateFormat.getDateInstance(3);
String datestr4 = dateformat4.format(date);
// datestr4 = 14-5-7
DateFormat dateformat5 = DateFormat.getDateInstance();
String datestr5 = dateformat5.format(date);
// datestr5 = 2014-5-7
SimpleDateFormat simpledateformat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String datestr6 = simpledateformat.format(date); //datestr6 = 2014年5月7日 15:24:07
推荐资料:http://www.cnblogs.com/ggjucheng/p/3352467.html
String、StringBuffer、StringBuilder
String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。
而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。
比如说
String a = “su”;
a += 1;
这里就会创建两个String对象。
StringBuilder:线程非安全的
StringBuffer:线程安全的
当我们在字符串缓冲去被多个线程使用是,JVM不能保证StringBuilder的操作是安全的,虽然他的速度最快,但是可以保证StringBuffer是可以正确操作的。当然大多数情况下就是我们是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的,就是速度的原因。
在Java中使用正则表达式的方法非常多,最简单的就是和字符串一起使用。在String中有四个方法可以使用正则表达式,它们是matches、split、replaceAll和replaceFirst。
matches方法可以判断当前的字符串是否匹配给定的正则表达式。如果匹配,返回true,否则,返回false。matches方法的定义如下:public boolean matches(String regex)。
split方法使用正则表达式来分割字符串,并以String数组的形式返回分割结果。split有两种重载形式,它们定义如下:
public String[] split(String regex)
public String[] split(String regex, int limit)
replaceAll和replaceFirst的定义如下:
public String replaceAll(String regex, String replacement)
public String replaceFirst(String regex, String replacement)
这两个方法用replacement替换当前字符串中和regex匹配的字符串。
推荐资料:http://blog.csdn.net/x_jian/article/details/4096029
http://www.blogjava.net/xzclog/archive/2006/09/19/70603.html
Java的I/O其实内容很多,我这里也只能稍微从类层次,框架的设计模式来论述。
总体来说,I/O可以分为字节流和字符流,不同在于字符流由字节流包装而来,在I/O读入之后经过JVM处理,把字节流转换成字符流。而字符流的字符采用哪种字符编码实现由JVM默认编码决定。
而每个流都分输入和输出,所以,总体来说,I/O有四个顶层类:
InputStream
OutputStream
Reader
Writer
而作为机器级别于机器直接交互的则是字节流:
InputStream
OutputStream
以IO的中间类,进行字节流到字符流的转换过渡,通常可作为字符流类的构造参数,可指定编码:
InputStreamReader
OutputStreamWriter
而字节流和字符流的缓冲容器来看有byte和char之分,所以派生出:
ByteArrayInputStream
ByteArrayOutputStream
CharArrayInputStream
CharArrayOutputStream
以上类只是表示流的表示形式,而在传输形式上还表现为是否有缓冲。所以,可以派生出子类为可缓冲类:
BufferInputStream
BufferOutputStream
BufferReader
BufferWriter
每一个顶层类都有对目录文件(File)的支持:
FileInputStream
FileOutputStream
FileReader
FileWriter
在Java中,一个强大的功能就是可以对对象进行序列化,转成二进制文件输出,也就是字节流输出而不是字符流输出,所以有顶层的InputStream和OutputStream派生类:
ObjectInputStream
ObjectOutputStream
流包括了节点流和过滤流,注意的是过滤流,可在读写的同时对数据进行操作,并且实现了同步操作,顶层过滤流类:
FilterInputStream
FilterOutputStream
其子类则在其基础上,对节点流进行封装,常见子类有:
BufferInputStream BufferOutputStream
DataInputStream DataOutputStream
LineNumberInputStream PrintStream
可参考子类的构造方法。
以上IO操作几乎就是把流装载到内存中,对其进行操作的时候是顺序读写,而需要随机读写时:
RandomAccessFile
从整个类框架的结构实现的接口来看,顶层类:
InputStream implements Closable,
OutputStream implements Closable, Flushable
Reader implements Closable, Readable
Writer implements Closable, Flushable, Appendable
各个接口方法:
Closable: close();
Flushable: flush();
Readable: read(CharBuffer cb);
Appendable: append();
从IO类使用时的规则来看,实现这些方法就是很自然的了,也是必须要实现的。如:流使用完必须关闭,流输出前必须刷新。
Java IO 框架中主要应用了两个设计模式:装饰模式和适配器模式。
姑且就把Java IO划分为元素和行为两个部分,元素则是适配,行为则是装饰加强。
适配器模式主要在于字节流到字符流的转换和元素的包装上,如类:InputStreamReader, CharArrayReader, FileReader, PipedReader, StringReader。
装饰模式主要在对流的强化之中,如缓冲、过滤、行定位等,如类:BufferedReader, FilterReader, LineNumberReader。
一个典型的例子就是:
BufferReader br = new BufferReader(new InputStreamReader(System.in));
综合了两种模式:把InputStream适配成InputStreamReader,再把InputStreamReader加强装饰城BufferedReader。
推荐资料:http://blog.csdn.net/evoline/article/details/14455173
http://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html
http://www.cnblogs.com/maxupeng/archive/2010/12/30/1922281.html
序列化是一个不太直观的概念,我们可以这么理解:
Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比 JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。Java对象序列 化就能够帮助我们实现该功能。
使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的"状态",即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。
除了在持久化对象时会用到对象序列化之外,当使用RMI(远程方法调用),或在网络中传递对象时,都会用到对象序列化。
一个简单的例子:
public class SimpleSerial {
public static void main(String[] args) throws Exception {
File file = new File("person.out");
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
Person person = new Person("John", 101, Gender.MALE);
out.writeObject(person);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
Object newPerson = in.readObject(); // 不用强制转换到Person类型
in.close();
System.out.println(newPerson);
}
}
推荐资料:http://www.blogjava.net/jiangshachina/archive/2012/02/13/369898.html
http://www.cnblogs.com/rollenholt/archive/2012/11/26/2789445.html
静态方法与静态类都是属于类而不是对象的,也就是说,不管类创建了多少个对象,所有的静态属性都只有一个。java类在加载时,程序首先会把该类的静态变量加载进内存中,也就是在堆空间中开辟一个区域专门存放。以后不管你new多少个类的对象,该静态变量永远都是在那里的。
对它的基本性质总结如下:
1. 若需要一个类的多个对象共享一个变量,则该变量需要使用 static 修饰.
2. 因为 static 修饰的变量为类的所有的实例所共享,所以 static 成员不属于某个类的实例, 而属于整个类.所以在访问权限允许的情况下,可以使用 "类名." 直接访问静态成员(成员包括属性和方法).
3. 注意: 在静态方法里只能直接调用同类中其它的静态成员(包括变量和方法),而不能直接访问类中的非静态成员.这是因为,对于非静态的方法和变量,需要先创建类的实例对象后才可使用,而静态方法在使用前不用创建任何对象.
4. 同 3 的道理: 静态方法不能以任何方式引用this和super关键字.
5. 非静态方法中可以直接来访问类的静态成员.
6. main() 方法是静态的,因此JVM在执行main方法时不创建main方法所在的类的实例对象.
7. 静态初始化指对类的静态属性进行初始化. 不应该在构造器中对静态成员进行初始化: 因为静态成员不因类的实例而改变.
Interface这个关键字产生一个完全抽象的类,没有提供任何的具体实现。它的出现是为了为了解决Java中只能单继承的问题。一个类可以实现多个接口。
在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是反过来却不是这样。并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、 设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。比如:如果我们进行一个图形编辑软件的开发,就会发现问题领域存在着圆、 三角形这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域是不存在的,它就是一个抽象概念。正是因为抽象的概念 在问题领域没有对应的具体概念,所以用以表征抽象概念的抽象类是不能够实例化的。
抽象类是普通的类与接口之间的一种中庸之道。
1.abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。
2.在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的。
3.abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系。
4.实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。
5.接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。
6.抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。
7.接口中的方法默认都是 public,abstract 类型的。
另外,我们知道抽象类是不能实例化的,也就是说如果存在一个抽象类abstract Class A,那么久不存在new A();的说法,那A有没有构造器呢,A的构造器有没有机会执行呢?(所以说,在创建新对象的时候,所有继承下来的构造函数都会被执行)
推荐资料:http://www.cnblogs.com/LittleRedPoint/p/3478023.html
方法的重写、重载与动态连接构成多态性。Java之所以引入多态的概念,原因之一是它在类的继承问题上和C++不同,后者允许多继承,这确实给其带来的非常强大的功能,但是复杂的继承关系也给C++开发者带来了更大的麻烦,为了规避风险,Java只允许单继承,派生类与基类间有IS-A的关系(即“猫”is a “动物”)。这样做虽然保证了继承关系的简单明了,但是势必在功能上有很大的限制,所以,Java引入了多态性的概念以弥补这点的不足,此外,抽象类和接口也是解决单继承规定限制的重要手段。同时,多态也是面向对象编程的精髓所在。
要理解多态性,首先要知道什么是“向上转型”。
我定义了一个子类Cat,它继承了Animal类,那么后者就是前者是父类。我可以通过
Cat c = new Cat();
实例化一个Cat的对象,这个不难理解。但当我这样定义时:
Animal a = new Cat();
这代表什么意思呢?
很简单,它表示我定义了一个Animal类型的引用,指向新建的Cat类型的对象。由于Cat是继承自它的父类Animal,所以Animal类型的引用是可以指向Cat类型的对象的。那么这样做有什么意义呢?
一、使用父类类型的引用指向子类的对象;
二、该引用只能调用父类中定义的方法和变量;
三、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用)
四、变量不能被重写(覆盖),”重写“的概念只针对方法,如果在子类中”重写“了父类中的变量,那么在编译时会报错。
推荐资料:http://www.cnblogs.com/LittleRedPoint/p/3478028.html
线程与进程的区别
多个进程的内部数据和状态都是完全独立的,而多线程是共享一块内存空间和一组系统资源,有可能互相影响。
线程本身的数据通常只有寄存器数据,以及一个程序执行时使用的堆栈,所以线程的切换比进程切换的负担要小。
多线程编程的目的,就是"最大限度地利用CPU资源",当某一线程的处理不需要占用CPU而只和I/O等资源打交道时,让需要占用CPU资源的其它线程有机会获得CPU资源。从根本上说,这就是多线程编程的最终目的。
了解一下java在多线程中的基础知识
1.Java中如果我们自己没有产生线程,那么系统就会给我们产生一个线程(主线程,main方法就在主线程上运行),我们的程序都是由线程来执行的。
2. 进程:执行中的程序(程序是静态的概念,进程是动态的概念)。
3. 线程的实现有两种方式,第一种方式是继承Thread类,然后重写run方法;第二种是实现Runnable接口,然后实现其run方法。
4. 将我们希望线程执行的代码放到run方法中,然后通过start方法来启动线程,start方法首先为线程的执行准备好系统资源,然后再去调用run方法。当某个类继承了Thread类之后,该类就叫做一个线程类。
5. 一个进程至少要包含一个线程。
6. 对于单核CPU来说,某一时刻只能有一个线程在执行(微观串行),从宏观角度来看,多个线程在同时执行(宏观并行)。
7. 对于双核或双核以上的CPU来说,可以真正做到微观并行。
Thread源码研究:
1) Thread类也实现了Runnable接口,因此实现了Runnable接口中的run方法;
2) 当生成一个线程对象时,如果没有为其设定名字,那么线程对象的名字将使用如下形式:Thread-number,该number将是自动增加的,并被所有的Thread对象所共享(因为它是static的成员变量)。
3) 当使用第一种方式来生成线程对象时,我们需要重写run方法,因为Thread类的run方法此时什么事情也不做。
4)当使用第二种方式生成线程对象时,我们需要实现Runnable接口的run方法,然后使用new Thread(new MyThread())(假如MyThread已经实现了Runnable接口)来生成线程对象,这时的线程对象的run方法或调就会MyThread类的run方法,这样我们自己编写的run方法就执行了。
说明:
Public void run(){
If(target!=null){
Target.run();
}
}
当使用继承Thread生成线程对象时,target为空,什么也不执行,当使用第二种方式生成时,执行target.run(),target为runnable的实例对象,即为执行重写后的方法
总结:两种生成线程对象的区别:
1.两种方法均需执行线程的start方法为线程分配必须的系统资源、调度线程运行并执行线程的run方法。
2.在具体应用中,采用哪种方法来构造线程体要视情况而定。通常,当一个线程已继承了另一个类时,就应该用第二种方法来构造,即实现Runnable接口。
此外,多线程还有一部分并发和同步的内容,这个就不讲了。
推荐资料:http://www.cnblogs.com/dennisit/p/3690378.html
http://blog.csdn.net/csh624366188/article/details/7318245
泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。通俗的说,就是泛泛的指定对象所操作的类型,而不像常规方式一样使用某种固定的类型去指定。泛型的本质就是将所操作的数据类型参数化,也就是说,该数据类型被指定为一个参数。这种参数类型可以使用在类、接口以及方法定义中。
泛型类中的类型参数几乎可以用于任何可以使用类名的地方。例如,下面是 java.util.Map 接口的定义的摘录:
public interface Map<K, V> {
public void put(K key, V value);
public V get(K key);
}
在使用泛型时,请注意其使用规则和限制,如下:
1、泛型的参数类型只能是引用类型,而不能是简单类型。比如,是不可使用的。
2、可以声明多个泛型参数类型,比如,同时还可以嵌套泛型,例如:>
3、泛型的参数类型可以使用extends语句,例如。
使用extends语句将限制泛型参数的适用范围。这里 ,则表示该泛型参数的使用范围是所有实现了collection接口的calss。如果传入一个则程序编译出错。
4、泛型的参数类型可以使用super语句,例如< T super List >。
super语句的作用与extends一样,都是限制泛型参数的适用范围。区别在于,super是限制泛型参数只能是指定该class的上层父类。这里表示该泛型参数只能是List和List的上层父类。
5、泛型还可以使用通配符,例如
使用通配符的目的是为了解决泛型参数被限制死了不能动态根据实例来确定的缺点。
举个例子:public class SampleClass < T extends S> {…}
假如A,B,C,…Z这26个class都实现了S接口。我们使用时需要使用到这26个class类型的泛型参数。那实例化的时候怎么办呢?依次写下
SampleClass<A> a = new SampleClass();
SampleClass<B> a = new SampleClass();
…
SampleClass<Z> a = new SampleClass();
这显然很冗余,还不如使用Object而不使用泛型,呵呵,是吧?
别着急,咱们使用通配符,就OK了。
SampleClass sc = new SampleClass();
只需要声明一个sc变量,很方便把!
到目前为止,Java 类库中泛型支持存在最多的地方就是集合框架。所有的标准集合接口都是泛型化的 —— Collection、List、Set 和 Map。类似地,集合接口的实现都是用相同类型参数泛型化的,所以 HashMap 实现 Map 等。
集合类也使用泛型的许多“技巧”和方言,比如上限通配符和下限通配符。例如,在接口 Collection 中,addAll 方法是像下面这样定义的:
interface Collection<V> {
boolean addAll(Collection<? extends V>);
}
该定义组合了通配符类型参数和有限制类型参数,允许您将 Collection 的内容添加到 Collection。
类的泛型
A B 处分别应该填什么?
① interface Hungry<E>{
void munch(E x);
}
② abstract class Animal{}
③ abstract class Plant{}
④ class Grass extends Plant{}
⑤ interface Carnivore<E extends __A__> extends Hungry<E>{}
⑥ interface Herbivore<E extends __B__> extends Hungry<E>{}
⑦ class Sheep extends Animal implements Herbivore<Grass>{
public void munch(Grass x){}
}
⑧ class Wolf extends Animal implements Carnivore<Sheep>{
public void munch(Sheep x){}
}
分析:这是一道典型的泛型例子,咋一看挺复杂,只要理清了思路,其实也很简单。先看⑦行,可知⑥行中的E = Grass;再看④行,可知B = Plant。同样由⑧行可知⑤行中的E = Sheep,再由⑦行可得出 A = Animal。
推荐资料:http://www.cnblogs.com/panjun-Donet/archive/2008/09/27/1300609.html
http://www.cnblogs.com/Fskjb/archive/2009/08/23/1552506.html
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
具体看例子:
import java.lang.reflect.Constructor;
class Person{
public Person() {
}
public Person(String name){
this.name=name;
}
public Person(int age){
this.age=age;
}
public Person(String name, int age) {
this.age=age;
this.name=name;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString(){
return "["+this.name+" "+this.age+"]";
}
private String name;
private int age;
}
class hello{
public static void main(String[] args) {
Class<?> demo=null;
try{
demo=Class.forName("Reflect.Person");
}catch (Exception e) {
e.printStackTrace();
}
Person per1=null;
Person per2=null;
Person per3=null;
Person per4=null;
//取得全部的构造函数
Constructor<?> cons[]=demo.getConstructors();
try{
per1=(Person)cons[0].newInstance();
per2=(Person)cons[1].newInstance("abc");
per3=(Person)cons[2].newInstance(10);
per4=(Person)cons[3].newInstance("abc",20);
}catch(Exception e){
e.printStackTrace();
}
System.out.println(per1);
System.out.println(per2);
System.out.println(per3);
System.out.println(per4);
}
}
推荐资料:http://blog.csdn.net/csh624366188/article/details/7309435
http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html
网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定。
但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。
Server端Listen(监听)某个端口是否有连接请求,Client端向Server 端发出Connect(连接)请求,Server端向Client端发回Accept(接受)消息。一个连接就建立起来了。Server端和Client 端都可以通过Send,Write等方法与对方通信。
对于一个功能齐全的Socket,都要包含以下基本结构,其工作过程包含以下四个基本的步骤:
(1) 创建Socket;
(2) 打开连接到Socket的输入/出流;
(3) 按照一定的协议对Socket进行读/写操作;
(4) 关闭Socket.(在实际应用中,并未使用到显示的close,虽然很多文章都推荐如此,不过在我的程序中,可能因为程序本身比较简单,要求不高,所以并未造成什么影响。
java在包java.net中提供了两个类Socket和ServerSocket,分别用来表示双向连接的客户端和服务端。这是两个封装得非常好的类,使用很方便。
客户端发送消息到服务端:
Socket clientToServer = new Socket(“192.168.1.1”, 0000);
//建立连接到socket的PrintWtiter
//字符数据与字节间的转换桥梁,可以连接String和Socket两端
PrintWriter writer = new PrintWriter(clientToServer.getOutputStream());
//写入数据
Writer.println(“***”);
客户端从服务端读取消息:
Socket serverToClient = new Socket(“192.168.1.1”, 0000);
//建立连接到socket上低层输入串流的InputStreamReader
InputStreamReader stream = new InputStreamReader(serverToClient.getInputStream());
//建立BufferReader来读取
BufferReader reader = new BufferReader(stream);
String message = reader.readLine();
推荐资料:Head First Java P471-485
Java 语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管 理。由于有个垃圾回收机制,Java中的对象不再有"作用域"的概念,只有对象的引用才有"作用域"。垃圾回收可以有效的防止内存泄露,有效的使用可以使 用的内存。垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清楚和回收,程序员不能 实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。
判断对象是否该被回收算法
1.引用计数算法
给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1,当引用失效时,计数器值就减1;任何时刻计数器值都为0时对象就表示它不可能被使用了。这个算法实现简单,但很难解决对象之间循环引用的问题,因此Java并没有用这种算法!这是很多人都误解了的地方。
2.根搜索算法
通过一系列名为“GC ROOT”的对象作为起始点,从这些结点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC ROOT没有任何引用链相连时,则证明这个对象是不可用的。如果对象在进行根搜索后发现没有与GC ROOT相连接的引用链,则会被第一次第标记,并看此对象是否需要执行finalize()方法(忘记finalize()这个方法吧,它可以被try-finally或其他方式代替的),当第二次被标记时,对象就会被回收。
三种垃圾回收器
1.串行收集器
使用单线程处理所有垃圾回收工作,因为无需多线程交互,所以效率比较高。但是,也无法使用多处理器的优势,所以此收集器适合单处理器机器。当然,此收集器也可以用在小数据量(100M左右)情况下的多处理器机器上。可以使用-XX:+UseSerialGC打开。
2.并行收集器
对年轻代进行并行垃圾回收,因此可以减少垃圾回收时间。一般在多线程多处理器机器上使用。使用-XX:+UseParallelGC.打开。
3.并发收集器
可以保证大部分工作都并发进行(应用不停止),垃圾回收只暂停很少的时间,此收集器适合对响应时间要求比较高的中、大规模应用。使用-XX:+UseConcMarkSweepGC打开。
推荐资料:http://blog.csdn.net/column/details/javavirtualmachine.html
参考资料:http://www.cnblogs.com/wxfvm/p/3676730.html
http://www.oschina.net/translate/everything-about-java-8
http://datalab.intyt.com/archives/370
http://www.importnew.com/10360.html