【Java6学习笔记1】基本概念
作者:gnuhpc
出处:http://www.cnblogs.com/gnuhpc/
1.基本名词
· Java Standard Edition (JSE)——标准版是快速开发和部署关键任务和企业应用程序的首选解决方案。
· Java Virtual Machine(JVM or VM)——Java虚拟机,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能模拟来实现的。Java语言最重要的特点就是可以在任何操作系统中运行。使用Java虚拟机就是为了支持与操作系统无关,在任何系统中都可以运行。Java虚拟机屏蔽了与具体操作系统平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。
----Java Hotspot Client VM,default, 主要用于减少应用启动时间以及内存的 footprint 。可以在命令行中指定使用$java -client
----Java HotSpot Server VM,和 Java HotSpot Client VM 类似,但是在最大性能上作了调整。用于长期运行的服务应用。可以在命令行中指定使用$java -server
2.基本工具
· javadoc—— 它从程序源代码中抽取类、方法、成员等注释形成一个和源代码配套的API帮助文档。也就是说,只要在编写程序时以一套特定的标签作注释,在程序编写完成后,通过Javadoc就可以同时形式程序的开发文档了。
· appletviewer——提供了一个Java运行环境,在其中可测试小应用程序Applet 。 appletviewer 读取包含小应用程序的HTML文件并在一个窗口中运行它们。
· jar——采用zip和ZLIB的压缩格式,将一系列程序相关的文件压缩为一个文件。优点是加快Applet的下载速度并且提高控件下载的安全性,因为所有的文件均在一个文件中,这样不会有不明文件,jar文件的压缩包包含jar文件结构信息,它包存在META-INF/MANIFEST.MF文件。该文件可以用来指明主类(main class)。
· jdb——Java中的调试工具。
· javah——从 Java 类生成 C 头文件和 C 源文件。这些文件提供了连接胶合,使 Java 和 C 代码可进行交互。
· javap——反汇编一个java字节代码文件, 返回有关可变部分和成员函数的信息
· extcheck—— 检测目标jar 文件与当前安装方式扩展jar 文件间的版本冲突。
3.基本数据类型
Boolean 布尔型 只有两个值true、false
Char 字符型 是Java中唯一一种无符号整数,16位,Java解释为Unicode
Byte 8位带符号整数 -128到127之间的任意整数
Short 16位带符号整数 -32768~32767之间的任意整数
Int 32位带符号整数 -231到231-1之间的任意整数
Long 64位带符号整数 -263到263-1之间的任意整数
Float 32位单精度浮点数 根据IEEE754-1985标准
Double 64位双精度浮点数 根据IEEE754-1985标准,Java默认的类型是double,所以在定义float时需要进行类型转换,(别忘了这个x是一个reference)float x=123.45f ;
4.面向对象数据类型
Class——类。
举例:
public class Simple {
int value;
void setValue(int setting) {
value = setting;
}
int getValue() {
return(value);
}
}
抽象类
public abstract class Clab {
int value;
int getValue() {
return(value);
}
abstract int getMaximum();
}
注意有三种方式使一个Class称为抽象Abstract:1)你可以在class前加上abstract。2)继承抽象类而不实现抽象方法。3)可以设计一个接口而不完成其中的方法。
Interface——接口,都是抽象方法。例如:
public interface Limits {
int getMaximum();
int getMinimum();
int getAverage();
}
enumeration——枚举
enum Position {
FRONT,
BACK,
LEFT,
RIGHT
}
public class PositionDemo {
static public void main(String arg[]) {
Position position;
position = Position.FRONT;
System.out.println("position=" + position);
}
}
annotation—— 标注或注释。并不影响程序的逻辑。它是对类、方法、变量等标注上一些属性,将来便于对这些元素进行查找、归类或统计等工作。 annotation本身就是类,定义起来也与interface相仿。
@interface MyAnno
{
String addr(); // 开发地点
String person(); // 联系人
}
这个annotation可以支持两个属性,都是String类型。如何用它修饰某元素(例如一个方法)呢?如下:
@MyAnno(addr="北京", person="小月")
public void f(){ ..... }
我们看到,annotation的使用很简单。只要用括号的方式给属性赋上值就行了。除了用它修饰方法外,当然也可以用它来修饰类。修饰什么就放在什么定义的前边。
很多时候,我们只需要一个属性。这时它应该叫value(),是String类型。
@interface MyA
{
String value();
}
此种情况下,在修饰某元素的时候,可以使用省略的写法:
@MyA("北京")
此时不需要写出 value="xxxx" 的格式。
又有些时候,我们根本不需要任何属性值的区分。只要知道有没有某个修饰符就足够了。此时更简化:
@interface InBeiJing{ }
....
@InBeiJing
public void f(){ ....}
值得一提的是,annotation定义的本身也可以被其它的annotation修饰。常用的:
// annotation本身也可被修饰
@Retention(RetentionPolicy.RUNTIME) //运行时可以查找修饰符
@Target(ElementType.METHOD) //只能用于修饰方法
// 定义一个annotation类型,与接口的定的极为相似。
@interface MyAnno
{
String addr(); // 开发地点
String person(); // 联系人
}
紧接的一个问题是:定义了annotation,也用它修饰了元素,如何检索这些标志呢?可以在多个场合实现。比如在类似于javadoc那样的处理程序中对源码进行查找;在class文件中进行查找;在运行时通过反射进行查找。
下面的例子是通过反射对类中具有指定的annotation的方法进行查找。
import java.lang.annotation.*;
import java.lang.reflect.*;
// annotation本身也可被修饰
@Retention(RetentionPolicy.RUNTIME) //运行时可以查找修饰符
@Target(ElementType.METHOD) //只能用于修饰方法
// 定义一个annotation类型,与接口的定的极为相似。
@interface MyAnno
{
String addr(); // 开发地点
String person(); // 联系人
}
// annotation 可以修饰类、方法、域。
public class AnnotationTest
{
@MyAnno(
addr = "北京",
person = "肖华"
)
public void f1(){ }
@MyAnno(
addr = "北京",
person = "王文举"
)
public void f2(){ }
@MyAnno(
addr = "杭州",
person = "肖华"
)
public void f3(){ }
public static void main(String[] args) throws Exception
{
//AnnotationTest类中,与"肖华"有关的方法有哪些?要求自动查找,而非人工查找。
for(Method m: AnnotationTest.class.getMethods()){
MyAnno an = m.getAnnotation(MyAnno.class);
if(an==null) continue;
if(an.person().equals("肖华")) System.out.println(m.getName());
}
}
}
5.构造方法
创建对象时自动调用。
例如:public class Circle {
double radius;
Circle() {
radius = 1.0;
}
Circle(double r) {
radius = r;
}
double getRadius() {
return(radius);
}
}
而在继承关系中实际上在没有参数时默认使用了老爸的构造方法,只不过没有写出而已,比如下边的Sphere(),而使用super()则很明显的使用了老爸的某一个构造方法,当然super(XX)是要放在儿子构造方法中的第一句话的。
例如:
public class Sphere extends Circle {
Sphere() {
}
Sphere(double r) {
super(r);
}
double getVolume() {
return((4.0/3.0) * Math.PI * radius * radius * radius);
}
}
当你看当如下的类定义时,说明你只能先继承一下才可以使用该类,因为只有儿子才能使用protected的构造类:
public class Prot {
protected Prot() {
}
}
6.Static类型
以变量X是否是Static,有下列两个图:
否
是
所有此类实例共享此静态变量,也就是说在类装载时,只分配一块存储空间,所有此类的对象都可以操控此块存储空间,当然对于final则另当别论了。
而对于方法,则表示无需本类的对象即可调用此方法。如下所示:
class Simple{
static void go(){
System.out.println("Go...");
}
}
public class Cal{
public static void main(String[] args){
Simple.go();
}
}
static变量有点类似于C中的全局变量的概念。值得探讨的是静态变量的初始化问题。
class Value{
static int c=0;
Value(){
c=15;
}
Value(int i){
c=i;
}
static void inc(){
c++;
}
}
class Count{
public static void prt(String s){
System.out.println(s);
}
Value v=new Value(10);
static Value v1,v2;// static定义的变量会优先于任何其它非static变量,不论其出现的顺序如何。
//以下为显式的静态变量初始化,这段代码只会初始化一次,且在类被第一次装载时。
static{
prt("v1.c="+v1.c+" v2.c="+v2.c);
v1=new Value(27);
prt("v1.c="+v1.c+" v2.c="+v2.c);
v2=new Value(15);
prt("v1.c="+v1.c+" v2.c="+v2.c);
}
public static void main(String[] args){
Count ct=new Count();
prt("ct.c="+ct.v.c);
prt("v1.c="+v1.c+" v2.c="+v2.c);
v1.inc();
prt("v1.c="+v1.c+" v2.c="+v2.c);
prt("ct.c="+ct.v.c);
}
}
7.Import语句
也许这个是最可能引起误会的语句了,我们通常认为Import是Load sth into program,其实在Java中,Import有如下特性:给Class或者Interface提供全名,仅次而已,若你在整个程序中都使用全名,则Import并不是必须的。Import在编译器去搜索简称时才起作用。 可以使用*表示全部引入,但是注意其并不支持子类的简写。没有运行消耗,只在编译阶段负责查找简写。默认总有一个Import语句:import.java.lang.*;对于静态方法,Import可以更为化简使用。
例如:
Import java.awt.Image;
Image im = new Image();
对于静态方法:
1. import static java.lang.Math.*;
2.
3. public class StaticImport1 {
4. public static void main(String[] args) {
5. double d = 2.5 , e = 3.0 ;
6.
7. System.out.println(min(d, e)); // 不需要使用 Math.min(d, e)
8. System.out.println(PI * pow(d, e));
9. }
10. }
8.this 和 super
this通常指当前对象,super则指父类的。当你想要引用当前对象的某种东西,比如当前对象的某个方法或某个成员,可用this来实现,最普遍的情况就是,在你的方法中的某个形参名与当前对象的某个成员有相同的名字,这时为了不至于混淆,你便需要明确使用this关键字来指明你要使用某个成员,使用方法是“this.成员名”,而不带this的那个便是方法中的本地形参。如果你想引用父类的某种东西,则用super莫属。
例如:
///Demo this
public class DemoThis{
private String name;
private int age;
DemoThis(String name,int age){
setName(name); //你可以加上this来调用方法,像这样:this.setName(name);但这并不是必须的
setAge(age);
this.print();
}
public void setName(String name){
this.name=name;//此处必须指明你要引用成员变量
}
public void setAge(int age){
this.age=age;
}
public void print(){
System.out.println("Name="+name+" Age="+age);//在此行中并不需要用this,因为没有会导致混淆的东西
}
public static void main(String[] args){
DemoThis dt=new DemoThis("Kevin","22");
}
}
class Person{
public int c;
private String name;
private int age;
protected void setName(String name){
this.name=name;
}
protected void setAge(int age){
this.age=age;
}
protected void print(){
System.out.println("Name="+name+" Age="+age);
}
}
///Demo super
public class DemoSuper extends Person{
public void print(){
System.out.println("DemoSuper:");
super.print();
}
public static void main(String[] args){
DemoSuper ds=new DemoSuper();
ds.setName("kevin");
ds.setAge(22);
ds.print();
}
}
而在构造函数中, this和super不再是像以前那样用“.”连接一个方法或成员,而是直接在其后跟上适当的参数,因此它的意义也就有了变化。以下例进行说明:
class Person{
public static void prt(String s){
System.out.println(s);
}
Person(){
prt("A Person.");
}
Person(String name){
prt("A person name is:"+name);
}
}
public class Chinese extends Person{
Chinese(){
super(); //调用父类构造函数(1)
prt("A chinese.");//(4)
}
Chinese(String name){
super(name);//调用父类具有相同形参的构造函数(2)
prt("his name is:"+name);
}
Chinese(String name,int age){
this(name);//调用当前具有相同形参的构造函数(3)
prt("his age is:"+age);
}
public static void main(String[] args){
Chinese cn=new Chinese();
cn=new Chinese("kevin");
cn=new Chinese("kevin",22);
}
}
super 后加参数的是用来调用父类中具有相同形式的构造函数,如1和2处。this后加参数则调用的是当前具有相同参数的构造函数,如3处。当然,在 Chinese的各个重载构造函数中,this和super在一般方法中的各种用法也仍可使用,比如4处,你可以将它替换为“this.prt”
9.final
final提供了诸如在C语言中定义常量的功能,final还可以让你控制你的成员、方法或者是一个类是否可被覆写或继承等功能。具体的:
final成员
当你在类中定义变量时,在其前面加上final关键字,这个变量一旦被初始化便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可再变。其初始化可以在两个地方,一是其定义处,也就是说在final变量定义时直接给其赋值,二是在构造函数中。这两个地方只能选其一。
还有一种用法是定义方法中的参数为final,对于基本类型的变量,这样做并没有什么实际意义,因为基本类型的变量在调用方法时是传值的,也就是说你可以在方法中更改这个参数变量而不会影响到调用语句,然而对于对象变量,却显得很实用,因为对象变量在传递时是传递其引用,这样你在方法中对对象变量的修改也会影响到调用语句中的对象变量,当你在方法中不需要改变作为参数的对象变量时,明确使用final进行声明,会防止你无意的修改而影响到调用方法。
另外方法中的内部类在用到方法中的参变量时,此参变也必须声明为final才可使用,例如:
public class INClass{
void innerClass(final String str){
class IClass{
IClass(){
System.out.println(str);
}
}
IClass ic=new IClass();
}
public static void main(String[] args){
INClass inc=new INClass();
inc.innerClass("Hello");
}
}
final方法
将方法声明为final,那就说明你已经知道这个方法提供的功能已经满足你要求,不需要进行扩展,并且也不允许任何从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。另外有一种被称为inline的机制,它会使你在调用final方法时,直接将方法主体插入到调用处,而不是进行例行的方法调用,例如保存断点,压栈等,这样可能会使你的程序效率有所提高,然而当你的方法主体非常庞大时,或你在多处调用此方法,那么你的调用主体代码便会迅速膨胀,可能反而会影响效率,所以你要慎用final进行方法定义。
final类
当你将final用于类身上时,你就需要仔细考虑,因为一个final类是无法被任何人继承的,那也就意味着此类在一个继承树中是一个叶子类,并且此类的设计已被认为很完美而不需要进行修改或扩展。对于final类中的成员,你可以定义其为final,也可以不是final.而对于方法,由于所属类为 final的关系,自然也就成了final型的。你也可以明确的给final类中的方法加上一个final,但这显然没有意义。final类与普通类的使用几乎没有差别,只是它失去了被继承的特性。final方法与非final方法的区别也很难从程序行看出,只是记住慎用。
参考文献:《Java中static、this、super、final用法简谈》