Java与C++比较概况

C++ Java
class Foo {          // 声明 Foo 类
public:
int x; // 成员变量 Foo(): x() { // Foo 的构造函数Constructor for Foo,
} // 初始化 x int bar(int i) { // 成员函数 bar()
return *i + x;
}
};
class Foo {               // 定义类 Foo
public int x = 0; // 成员变量,
// 以及其值的初始化
public Foo() { // Foo的构造函数
} public int bar(int i) {// 成员方法 bar()
return 3*i + x;
}
}
Foo a;
// 声明 a 为一个 Foo 类的对象值,
// 使用其缺省的构造函数
// 如果你想要用其他的构造函数,
// 你可以用 "Foo a(args);"
Foo a;
// 声明 a 为一个 Foo 类的对象的引用
a = new Foo();
// 使用缺省的构造函数初始化
// 如果你想要用其他的构造函数,
// 你可以用 "Foo a = new Foo(args);"

Foo b = a;
// 拷贝 a 的内容到一个新的 Foo 类的变量 b 当中;
// 另一种可以选择的语法是 "Foo b(a)"

Foo b = a.clone();
// 拷贝所有a这个实例的成员到b,当且仅当,
// Foo 实现了一个 public 的 clone() 方法,
// 并且 clone() 返回一个新的这个对象的拷贝

a.x = ; // 修改 a 对象

a.x = 5; // 修改 a 对象
cout << b.x << endl;
// 输出 0,因为 b 和 a 是两个对象
System.out.println(b.x);
// 输出 0,因为 b 和 a 是两个对象
Foo *c;
// 声明 c 为指向一个 Foo 类对象的指针(初始值是
// 未定义的;可能指向任何地方)
Foo c;
// 声明 c 为一个指向 Foo 对象的指针
// (如果 c 是一个类的成员,那么初始值为空;
// 如果 c 是一个局部变量那么你在使用之前必须
// 对它进行初始化)
c = new Foo();
// 将 c 绑定为一个新的 Foo 对象的引用
c = new Foo();
// 将 c 绑定为一个新的 Foo 对象的引用
Foo *d = c;
// 将 d 绑定为和 c 同一个对象的引用
Foo d = c;
// 将 d 绑定为和 c 同一个对象的引用
c->x = ;
// 修改 c 指向的对象
c.x = 5;
// 修改 c 指向的对象
a.bar();  // 对 a 调用 Foo::bar()
c->bar(); // 对 *c 调用 Foo::bar()
a.bar(5); // 对 a 调用 Foo.bar()
c.bar(5); // 对 c 调用 Foo.bar()
cout << d->x << endl;
// 输出 5,因为 d 引用的对象和 c 一样
System.out.println(d.x);
// 输出 5,因为 d 引用的对象和 c 一样

-- 来自于wiki - Comparison of Java and C++  en  中文

Java具有如下一些特性:

1. Java中基本数据为值类型,数组、枚举、类、接口均为引用类型。
2. Java中没有全局变量、全局函数、没有struct,没有union,所有东西必须写入类中。
3. Java用包代替了命名空间,用import关键字来导入外部包进行使用。
4. Java所有对象都从Object类单根继承,支持接口多继承。
5. Java没有预处理过程(不存在宏)、没有goto语句、没有指针、没有析构函数,不支持函数缺省参数,不支持运算符重载。

Java基本类型及其包装类

boolean [1字节]

boolean flag = false;

Boolean

Boolean bObj1 = Boolean.TRUE;
Boolean bObj2 = new Boolean(false);

char [2字节 16位Unicode]

char ch1 = 'a';
char ch2 = '\141'; // 8进制,'a'
char ch3 = '\u0061'; // 16进制,'a'
char ch4 = '\n';
char ch5 = '中';

Character

Character chObj1 = new Character('a');
char ch2 = Character.toUpperCase('b');

byte [1字节]

byte a = 35;

Byte

Byte.MIN_VALUE - Byte.MAX_VALUE

Byte b1 = new Byte("23");

short [2字节]

short a = 870;

Short

Short.MIN_VALUE - Short.MAX_VALUE

Short s1 = new Short("315");

int [4字节]

int a = 56;  // 十进制
int b = 0210; // 八进制
int c = 0x2ff; // 十六进制

Integer

Integer.MIN_VALUE - Integer.MAX_VALUE

Integer intObj = new Integer(56);
int intVal = intObj.intValue();

long [8字节]

long m = 356;
long n = 86L;

Long

Long.MIN_VALUE - Long.MAX_VALUE

Long s1 = new Long("-98166");

float [4字节]

float f = 3.5f;

Float

Float.MIN_VALUE - Float.MAX_VALUE

Float.NEGATIVE_INFINITY - Float. POSITIVE_INFINITY

0.0f/0.0f   Float.NaN

double [8字节]

double d1 = 2.56;
double d2 = 2.3e-2

Double

Double.MIN_VALUE - Double.MAX_VALUE

Double.NEGATIVE_INFINITY- Double. POSITIVE_INFINITY

0.0/0.0    Double.NaN

基本类型的大小固定,与平台无关,因此Java没有像C++那样提供sizeof关键字来获取类型和对象的大小。

另外,Java不提供无符号的数据类型(unsigned)。

右移位运算符>>>

与逻辑右移位运算符功能类似,只是在左端末尾插入零值。>>则会在移位的同时插入符号位(即算术移位)

int n1 = -1;      //n1=0xFFFFFFFF
int n2 = n1>>1; //n2=0xFFFFFFFF
int n3 = n1>>>1; //n3=0x7FFFFFFF

函数参数传递

Java函数参数没有指针传递、引用传递,只有值传递。

值类型参数会产生一个值类型副本,引用类型参数会产生一个引用类型副本(注意:引用类型间赋值不会产生新的对象,因此不会触发拷贝构造函数调用)

因此,想通过函数来实现两个数值变量或对象的交换是不行的,如下:

/***** AppMain.java *****/
public class AppMain
{
public static void fun(int n, Integer o)
{
n = 1;
o = new Integer(1);
} public static void swapInt(int a, int b)
{
int c = a;
a = b;
b = c;
} public static void swapInteger(Integer oa, Integer ob)
{
Integer oc = oa;
oa = ob;
ob = oc;
} public static void main(String[] args)
{
int n1 = 0;
Integer on1 = new Integer(0);
System.out.println("n1="+n1 + ", on1="+on1);//n1=0, on1=0
fun(n1, on1);
System.out.println("n1="+n1 + ", on1="+on1);//n1=0, on1=0 int n2 = 1;
Integer on2 = new Integer(1);
System.out.println("n1="+n1 + ", n2="+n2); //n1=0, n2=1
System.out.println("on1="+on1 + ", on2="+on2);//on1=0, on2=1
swapInt(n1, n2);
swapInteger(on1, on2);
System.out.println("n1="+n1 + ", n2="+n2); //n1=0, n2=1
System.out.println("on1="+on1 + ", on2="+on2);//on1=0, on2=1
}
}

其实,通过函数来实现两个数值变量或对象的交换也是有办法的(包裹:将要交换的数值变量或对象包裹到一个数组或类中)

/***** AppMain.java *****/
public class AppMain
{
public static void swapIntTrue(int[] a, int[] b)
{
int c = a[0];
a[0] = b[0];
b[0] = c;
} public static void swapIntegerTrue(Integer[] oa, Integer[] ob)
{
Integer oc = oa[0];
oa[0] = ob[0];
ob[0] = oc;
} public static void main(String[] args)
{
int n1 = 0;
int n2 = 1;
Integer on1 = new Integer(0);
Integer on2 = new Integer(1); int nArray1[] = new int[1];
int nArray2[] = new int[1];
nArray1[0] = n1;
nArray2[0] = n2;
System.out.println("n1="+n1 + ", n2="+n2);//n1=0, n2=1
swapIntTrue(nArray1, nArray2);
n1 = nArray1[0];
n2 = nArray2[0];
System.out.println("n1="+n1 + ", n2="+n2);//n1=1, n2=0 Integer onArray1[] = new Integer[1];
Integer onArray2[] = new Integer[1];
onArray1[0] = on1;
onArray2[0] = on2;
System.out.println("on1="+on1 + ", on2="+on2);//on1=0, on2=1
swapIntegerTrue(onArray1, onArray2);
on1 = onArray1[0];
on2 = onArray2[0];
System.out.println("on1="+on1 + ", on2="+on2);//on1=1, on2=0
}
}

自动封装(Autoboxing)&自动拆封(Autounboxing)

/***** AppMain.java *****/
public class AppMain
{
public static int autoBoxing(Integer o)
{
int sum = 2 + o;//自动拆封
return sum;
} public static Integer autoUnBoxing(int n)
{
Integer o = new Integer(n);
o += 2;//自动封装
return o;
} public static void main(String[] args)
{
Integer oRet = autoBoxing(1);//参数与返回值均自动封装 int nRet = autoUnBoxing(oRet);//参数与返回值均自动拆封
}
}

数组

// -----------------  一维数组  ------------------
int nScores[] = {1,2,3,4,5,6,7,8,9,0};
String[] strContents = {"How", "Are", "You","?"};
float fDistances[] = new float[3]; // ----------------- 二维数组 ------------------
int nMatrix[][] = {
{0, 1, 2},
{3, 4, 5},
{6, 7, 8}
};
double[][] codes = new double[5][5]; long[] secs[] = new long[2][];
secs[0] = new long[3];
secs[1] = new long[4]; // ----------------- 数组长度 ------------------
int nWeek[] = {1, 2, 3, 4, 5, 6, 7};
int nLength = nWeek.length; // nLength = 7 // ----------------- 数组拷贝 ------------------
int nScores[] = {1,2,3,4,5,6,7,8,9,0};
int nScores2[] = new int[12];
System.arraycopy(nScores, 0, nScores2, 2, 8); // nScores2 = { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0,}

Arrays为数组的公用工具类,里面有大量静态成员函数供数组使用。

注释

// 单行注释
/* 块注释 */
/** doc注释(会被javadoc辨别)*/

package与import

package是Java提供的一种封装机制,可将一组类和接口封装在一个package中,缺省访问符修饰的类/接口、变量、方法在package内可见。package有效地管理类名空间,可防止类名冲突。

package语句作为Java源文件的第一条语句,指明该文件中定义的类/接口所在的包

package com.JavaApp; // 该源文件需要放在src/com/JavaApp目录中

如果源文件中没有package语句,则为无名包,该源文件存放在src/目录中

为了防止在使用类时带上长长的包路径,可使用import将包路径导入到当前源文件中

import java.applet.Applet;
import java.awt.*;

for、break、continue增强

void breakTest()
{
int sum = 0;
int[] code = {0,1,2,3,4,5};
// 针对数组、集合、枚举的for循环形式 JDK1.5之后增加
for (int e : code)
{
sum += e;
if (sum >30)
{
break;
}
} L1:for(int i=0; i<100; i++)
{
L2:for(int j=0; j<100; j++)
{
if (i==50 && j==80)
{
// 跳出L1层循环
break L1;
}
}
}
} void continueTest()
{
int sum = 0;
while(sum<1000)
{
if (++sum>100)
{
continue;
}
} C1:for(int i=0; i<100; i++)
{
C2:for(int j=0; j<100; j++)
{
if (i==50 && j==80)
{
// 继续C1层循环
continue C1;
}
}
}
}

字符串(16位unicode)

String  处理不变的字符串,任何对String的改变都会引发新的String对象的生成

String s1 = "hello";            // 静态创建字符串对象
String s2 = new String("你好"); // 动态创建字符串对象
int ns1Len = s1.length(); // ns1Len = 5
int ns2Len = s2.length(); // ns2Len = 2 String s3 = "hello";
String s4 = new String("你好"); String s5 = "Hello"; if (s1==s3) // true -s1与s3是否指向同一个对象
{
System.out.println("yes!! s1==s3");
}
if (s2==s4) // false -s2与s4是否指向同一个对象
{
System.out.println("yes!! s2==s4");
} if (s1.equals(s5)) // false -s1与s5的字符串内容是否完全一致
{
System.out.println("yes!! s1,s5 has same string value.");
}
if (s2.equals(s4)) // true -s2与s4的字符串内容是否完全一致
{
System.out.println("yes!! s2,s4 has same string value.");
} if (s1.equalsIgnoreCase(s5)) // true -忽略大小写,s1与s5的字符内容是否一致
{
System.out.println("yes!! s1,s5 has same string value when ignore case.");
}
if (s2.equalsIgnoreCase(s4)) // true -忽略大小写,s2与s4的字符内容是否一致
{
System.out.println("yes!! s2,s4 has same string value when ignore case.");
}

String类的"="、"+"、"+=",看似运算符重载,实际只是java编译器做了一点手脚,对String的运算符做了特殊处理。

String s = "Hello ";
s += "World!"; // 编译器转换成s = (new StringBuilder()).append(s).append("World!").toString();

StringBuffer   处理可变字符串(线程安全),不可被继承(final)

StringBuilder  处理可变字符串(线程不安全,拥有更高的性能),不可被继承(final),JDK1.5引入

StringBuffer与StringBuilder在使用上几乎没有区别

StringBuffer sb1 = new StringBuffer("Hello ");
sb1.append("World!");
String str1 = sb1.toString(); // Hello World! StringBuilder sb2 = new StringBuilder("Hello ");
sb2.append("World!");
String str2 = sb2.toString(); // Hello World!

成员权限控制

---------------------------- 访问修饰符 ---------------------------

#          当前类    同一package   子类     其他package

public           √            √             √              √

protected     √            √             √              ×

缺省             √             √             ×             ×

private         √             ×             ×             ×

---------------------------------------------------------------------

访问修饰符 修饰符 class 类名称 extends 父类名称 implement 接口名称1, 接口名称2

1、每个类文件仅能有一个public class,可以存在多个其他的缺省class 
2、public class的名称(包含大小写)必须和其类文件同名
3、一个类文件(*.java)中可以不存在public class
4、top class不能是private和protected(注:内部类可以)

修饰符:

final 当前类不能被继承
abstract 抽象类,不能被实例化;抽象类中不一定包含抽象方法,但包含了抽象方法的类一定要声明为抽象类
static 静态类;只有内部类才能定义为静态类

内部类
1、内部类拥有top class的所有特性
2、内部类可以是public、缺省、protected、private的
3、内部类可以访问其外部类的成员变量、方法,及所在外部类的其它内部类

静态类
1、只有内部类才能声明为static,也可以说是静态内部类
2、只有静态内部类才能拥有静态成员,普通内部类只能定义普通成员
3、静态类跟静态方法一样,只能访问其外部类的静态成员
4、如果在外部类的静态方法中访问内部类,这时候只能访问静态内部类

其他类中使用内部类
1、访问内部类,必须使用:外部类.内部类
2、静态内部类可以直接new
3、普通内部类必须绑定在其外部类的实例上

class A 
{
static class Ainner1 {}
class Ainner2 {}
} class B
{
public test()
{
A.Ainner1 m1 = new A.Ainner1(); A m = new A();
A.Ainner2 m2 = m.new Ainner2();
}
}

[静态] 成员变量

class A
{
// 调用顺序 【1】
public static int MAX_SIZE = 100;
static final int WTN_TOTAL = 500; // static常量类型,定义时必须进行初始化
public int m_nVar = 9;
final boolean m_switch = false; // 常量类型,定义时进行初始化
final int m_nVarConst; // final空白(只声明,不赋值),可在构造函数中为不同对象赋不同的值 protected String m_strName = "A";
private boolean m_bSex; float m_fDis = 8.0f; transient short m_shFlag = 10; // 告诉编译器,在类对象序列化的时候,此变量不需要持久保存
public static volatile boolean m_bRet; // 多线程时,要求编译器优化时保证对此变量的修改能够被正确的处理 // 调用顺序 【2】
// 类成员变量初始化器,可以有多个,按照先后顺序执行,但仅被初始化一次(当JVM加载类时执行)
static
{
MAX_SIZE = 240;
}
static
{
} // 成员变量初始化器;运行于父类构造函数之后,自身构造函数之前
{
m_nVar = 100;
m_strName = "AA";
m_bSex = false;
m_fDis = 12.0f;
} // 调用顺序 【3】
public A()
{
MAX_SIZE = 200;
m_nVar = 99;
m_strName = "a";
m_bSex = true;
m_fDis = 10.0f;
// final空白,必须在构造函数中赋初值
m_nVarConst = 0;
} public A(int nVar)
{
// final空白,必须在构造函数中赋初值
// 可在构造函数中为不同对象赋不同的值
// 一旦被赋值,就不可再改变
m_nVarConst = nVar;
} // 参数nVar1不可在函数体中被修改
public void fun1(final int nVar1, int nVar2)
{
// nSum被赋值后不能被修改
final int nSum = nVar1 + nVar2; // static int nResult = 100; -- 非法,java不允许static局部变量
}
}

[静态] 成员函数

class B
{
int m_nVar = 0;
static short m_shVar = 10; // 无参构造函数
public B()
{
m_nVar = 1;
}
// 有参构造函数
public B(int nVar)
{
m_nVar = nVar;
}
// 拷贝构造函数
public B(B other)
{
this.m_nVar = other.m_nVar;
}
// finalize方法调用时机
// 1、显式的调用finalize方法
// 2、程序退出时为每个对象调用一次finalize方法
// 3、JVM按照某种策略(如内存不够)来进行垃圾回收时调用finalize;程序员可通过调用System.gc()来建议JVM进行垃圾回收
protected void finalize()
{
} // final类成员函数,不能被子类重写
// 在其函数体内,只能访问类成员变量和类成员函数,不能使用this、super等关键字
public final static void sFunc1()
{
m_shVar = 5;
} // 类成员函数;在其函数体内,只能访问类成员变量和类成员函数,不能使用this、super等关键字
public static void sFunc2(int nVar)
{
m_shVar += nVar;
}
// final成员函数,可被子类继承,但不能被重写
public final void func1(int nVar)
{
m_shVar = (short)nVar;
m_nVar = nVar;
} // 成员函数
public void func2(int nVar)
{
m_shVar = (short)nVar;
m_nVar = nVar; // 调用参数不定成员函数
fun3();
fun3(1);
fun3(1,2);
fun3(1,2,3);
fun3(new int[]{1,2});
} // 参数不定成员函数
// 1、如果存在fun3()、fun3(int)等函数,在调用fun3时,优先匹配定长参数的函数
// 2、可变参数必须为函数参数列表中的最后一项
public void fun3(int... an)
{
for(int i=0;i<an.length;i++)
{
System.out.println(an[i]);
}
} // java native方法及JNI实例
// 用native定义的方法没有实现,而大多数情况下该方法的实现是用C、C++编写的
// JNI提供了运行时加载一个native方法的实现,并将其于一个Java类关联的功能
public native void displayHelloWorld(); /*1、synchronized关键字的作用域有二种:
1)对象实例范围。synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法
(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。
然而,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
2)类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static方法
(如果一个类有多个synchronized static方法,只要一个线程访问了其中的一个synchronized static方法,其它线程不能同时访问这个类中任何一个synchronized static方法)。
它可以对类的所有对象实例起作用。 2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
用法是:
synchronized(B.class){区块},它的作用域是类B;
synchronized(this){区块},它的作用域是当前this对象;
synchronized(String obj){区块},它的作用域是当前String对象; 3、synchronized关键字不能被继承的,也就是说,基类的synchronized f()方法在继承类中并不自动是synchronized f(),而是变成了f()。
继承类需要显式的指定为synchronized方法。*/ // synchronized static 方法
public static synchronized void synFunc1()
{
}
// synchronized方法
public synchronized void synFunc2()
{
}
// synchronized块
public void synFun3(String strVar)
{
// 获得当前类锁。有线程访问时以下同步代码块时,其它线程的访问都被暂时阻塞
synchronized(B.class)
{
System.out.println("syn class!");
} System.out.println("Hello..."); // 获得当前strVar对象锁。有线程访问时以下同步代码块时,其它线程的访问都被暂时阻塞
synchronized(strVar)
{
System.out.println("syn var obj!");
} System.out.println("World..."); // 获得当前this对象锁。有线程访问时以下同步代码块时,其它线程的访问都被暂时阻塞
synchronized(this)
{
System.out.println("syn this!");
}
}
} // 抽象函数
abstract class C
{
// 不能将static方法、final方法或者类的构造器方法声明为abstract
public abstract void aFunc(); public int func(int a, int b)
{
return a+b;
}
} // 抽象类不能实例化,被其他类继承后,必须实现抽象类中的抽象函数
class D extends C
{
public void aFunc()
{
}
}

类继承

class CParent
{
String m_strName = "Parent";
int m_nParentAge; public CParent(int nAge)
{
m_nParentAge = nAge;
} public void fun1()
{
} public void fun2()
{
}
} class CChildren1 extends CParent
{
// CParent中的m_strName变量被隐藏
String m_strName = "Children";
int m_nChildrenAge; public CChildren1(int nAge)
{
// 由于父类没有缺省参数的构造函数,必须在构造函数中显示构造父类
super(nAge);
} // 重写CParent中的fun1方法
// 1.重写的方法(子类)不能比被重写的方法(父类)有更严格的访问权限
// 2.重写的方法(子类)不能比被重写的方法(父类)产生更多的异常
public void fun1()
{
// this用来引用当前对象,super用来引用当前对象的父类 // 强制调用CParent的fun1方法
super.fun1();
// 强制访问CParent的m_strName
String str1 = super.m_strName; // 访问自己的m_strName
String str2 = this.m_strName;
// 访问自己的m_strName时,可以不带上this
String str3 = m_strName;
}
} class CChildren2 extends CParent
{
public CChildren2(int nAge)
{
super(nAge);
}
} class CGrandChildren1 extends CChildren1
{
public CGrandChildren1(int nAge)
{
super(nAge);
}
} public class AppMain
{
// instanceof可以判定一个对象是否属于某个类的实例
// 在判定时应循序特殊到一般的原则,先判断子类,再判断父类
static int GetClassType(CParent obj)
{
if (obj instanceof CGrandChildren1)
{
return 11;
}
else if (obj instanceof CChildren1)
{
return 1;
}
else if (obj instanceof CChildren2)
{
return 2;
} return 0;
} public static void main(String[] args)
{
CParent c1 = new CChildren1(0);
CParent c2 = new CGrandChildren1(0);
int nClsType = GetClassType(c1); // 返回1
nClsType = GetClassType(c2); // 返回11 // 将c1强制转成CChildren1类型,这个过程叫造型
/* 如果c1为CChildren1类型时,代码不会有问题;若不是,系统会抛出ClassCastException的异常
因此,在造型之前使用instanceof进行判断是明智之举 */
CChildren1 cc = (CParent)c1;
}
}

接口

访问修饰符 interface 接口名称 extends 接口名称1, 接口名称2

访问修饰符:public  缺省

与类一样,public接口必须定义到自己独立的源文件中或类的内部,缺省接口可定义在任何位置

1、interface中数据成员均为公共类常量,具有public、static、final属性
2、interface中方法成员均为公共抽象方法,具有public、abstract属性
3、在接口继承关系中,如果子接口中定义了与父接口同名的常量和相同的方法,则父接口中的常量将被隐藏,方法被重写

interface E
{
int MAX_SIZE = 100;
String NAME = "E"; void inter();
void interE();
} // 接口F必须写到F.java中
public interface F extends E
{
String NAME = "F"; // 接口E的NAME被隐藏 void inter(); // 接口E的inter()方法被重写
void interF();
} // 使用接口E,在new时重写接口E的方法
public static void main(String[] args)
{
E e = new E()
{
public void interE()
{
}
};
}

枚举

枚举从JDK1.5才引进;与类一样,public枚举必须定义到自己独立的源文件中或类的内部,其他类型的枚举可定义在任何位置。

枚举具有类的绝大数特性,但也有一些特殊之处:

1、枚举常量具有public、static、final属性
2、枚举的构造函数必须为private
3、无法在外部或枚举内部new一个枚举对象
4、不支持类继承,支持接口多继承

public enum Week {Monday, Tuesday, Wednesday, Thursday,  Friday, Saturday, Sunday};
////////////////////////////////////////////////////////////////////////
enum Currency
{
Penny(1), Nickle(5), Dime(12), Quarter(100);
private int m_nValue; private Currency(int nVal)
{
m_nValue = nVal;
}
int GetValue()
{
return m_nValue;
}
} ////////////////////////////////////////////////////////////////////////
interface IBase1
{
void fun1();
} interface IBase2
{
void fun2();
}
enum Planet implements IBase1, IBase2
{
Mercury (3.303e+23, 2.4397e6),
Venus (4.869e+24, 6.0518e6),
Earth (5.976e+24, 6.37814e6),
Mas (6.421e+23, 3.3972e6),
Jupiter (1.9e+27, 7.1492e7),
Saturn (5.688e+26, 6.0268e7),
Uranus (8.686e+25, 2.5559e7),
Neptune (1.024e+26, 2.4746e7); private final double m_mass;
private final double m_radius;
Planet(double mass, double radius)
{
m_mass = mass;
m_radius = radius;
} public void fun1()
{
}
public void fun2()
{
}
} ////////////////////////////////////////////////////////////////////////
public static void main(String[] args)
{
Currency usCoin = Currency.Dime;
switch (usCoin)
{
case Currency.Penny:
System.out.println("Penny");
break;
case Currency.Nickle:
System.out.println("Nickle");
break;
case Currency.Dime:
System.out.println("Dime");
break;
case Currency.Quarter:
System.out.println("Quarter");
break;
} if (Currency.Quarter == usCoin)
{
System.out.println("Quarter coin");
} for(Currency coin: Currency.values())
{
System.out.println("coin: " + coin);
}
}

异常

所有的异常类必须从Throwable派生,异常分为两大类:一类是unchecked异常(橙色部分):
1、Error类异常由JVM生成并抛出(如:动态链接错误),我们不能在编程层面上解决Error,所以应该直接退出程序。
2、RuntimeException(及其衍生类)是Java程序自身造成的,RuntimeException完全可以通过修正Java程序避免。这类异常,Java编译器不强制要求程序员对其捕获和处理。

另外一类就是checked异常(淡蓝色部分):
Java编译器要求程序员必须捕获或声明所有的这类非运行时异常(如:文件找不到造成的IOException)。

/******************* 自定义异常 *******************/
class ExceptionSelf1Base extends Exception
{
private String m_strExpInfo;
ExceptionSelf1Base(String strVal)
{
m_strExpInfo = strVal;
} public String toString()
{
return "Exception: " + m_strExpInfo;
}
} class ExceptionSelf2Base extends Exception
{
private int m_nExpInfo;
ExceptionSelf2Base(int nVal)
{
m_nExpInfo = nVal;
} public String toString()
{
return "Exception: " + m_nExpInfo;
}
} class ExceptionSelf1 extends ExceptionSelf1Base
{
public ExceptionSelf1(String strVal)
{
super(strVal);
}
}
/******************* 抛出异常 *******************/
class ExceptionTest
{
// 需要通过throws关键字声明函数内的所有抛出的checked异常
public void throwExp(int nMode) throws ExceptionSelf1,ExceptionSelf1Base,ExceptionSelf2Base
{
if (nMode < 0)
{
ExceptionSelf1Base e1 = new ExceptionSelf1Base("nMode < 0");
throw e1;
}
else if (nMode < 100)
{
ExceptionSelf2Base e2 = new ExceptionSelf2Base(100);
throw e2;
} ExceptionSelf1 e = new ExceptionSelf1("nMode >= 100");
throw e;
}
}
/******************* 异常处理 *******************/
public class AppMain
{
public static void main(String[] args)
{
ExceptionTest expTest = new ExceptionTest();
try
{
expTest.throwExp(100);
}
// 捕捉异常时,需要按照特殊到一般的顺序进行捕捉
catch (ExceptionSelf1 e)
{
}
catch (ExceptionSelf1Base e)
{
}
catch (ExceptionSelf2Base e)
{
}
catch (Exception e)
{
}
// finally为非必需的块
// 进入try块后,无论发生还是不发生异常,finally块中的代码都要被执行,提供了统一的出口
finally
{
}
}
}

泛型

泛型从JDK1.5才引进;经常被称为参数化类型,它能够像方法一样接受不同类型的参数。

泛型中的通配符:
(1) 泛型中可以使用"?"通配符作为参数,表示该泛型可以接受任意类型的数据
(2) 上届通配符:只允许类A或类A的子类作为参数传入;表示方式:泛型类型<? extends A>
(3) 下届通配符:只允许类A或类A的父类作为参数传入;表示方式:泛型类型<? super A>

如果想从一个数据类型里获取数据,使用 ? extends A 通配符
如果想把对象写入一个数据结构里,使用 ? super A 通配符
如果既想存又想取,那就不要用通配符

/***** AppMain.java *****/
import java.util.*;
public class AppMain
{
public static void main(String[] args)
{
//ArrayList<?> gList1 = new ArrayList<?>();//编译错误,通配符修饰的泛型不能用来直接创建对象
ArrayList<String> gStrList2 = new ArrayList<String>();
gStrList2.add("1");
ArrayList<?> gList2 = gStrList2;
Object objVal = gList2.get(0); //通配符修饰的泛型可以读取数据到Object类型
//gList2.add("2"); //编译错误,【?】通配符修饰的泛型不能写入任何类型数据 //ArrayList<? extends Number> geList1 = new ArrayList<? extends Number>();//编译错误,通配符修饰的泛型不能用来直接创建对象
ArrayList<Integer> geIntList2 = new ArrayList<Integer>();
geIntList2.add(1);
List<? extends Number> geList2 = geIntList2;
Object objVa2 = geList2.get(0); //通配符修饰的泛型可以读取数据到Object类型
Number nVal = geList2.get(0); //【上届通配符】修饰的泛型可以读取数据到Number类型
//geList2.add(new Integer(2)); //编译错误,【上届通配符】修饰的泛型不能写入任何类型数据 //ArrayList<? super Integer> gsList1 = new ArrayList<? super Integer>();//编译错误,通配符修饰的泛型不能用来直接创建对象
ArrayList<Integer> gsIntList2 = new ArrayList<Integer>();
gsIntList2.add(1);
List<? super Integer> gsList2 = gsIntList2;
Object objVal3 = gsList2.get(0); //通配符修饰的泛型可以读取数据到Object类型
//Integer nVal2 = gsList2.get(0); //编译错误,【下届通配符】修饰的泛型不能读取数据到除Object类型中
gsList2.add(2); //【下届通配符】修饰的泛型可以写入Integer及其父类类型数据 /*** 自定义泛型 ***/
//Gencs<CString,String,String> gen1 = new Gencs<Float,String,String>();//编译错误,参数1必须为Number或其子类
Gencs<Integer,String,String> gen2 = new Gencs<Integer,String,String>();
Gencs<Float,String,String> gen3 = new Gencs<Float,String,String>();
gen3.setX(3.0f);
Float fGen3 = gen3.getX();
Object oGen3 = gen3.getX();
//Integer iGen3 = gen3.getX();//编译错误,返回值为Float类型
//gen3.setX(3);//编译错误,必须传入Float类型参数
}
} class Gencs<X extends Number, Y, Z>
{
private X m_x;
//static Y m_y; //编译错误,不能用在静态变量中
public X getX()
{
return m_x;
} public void setX(X x)
{
m_x = x;
}
public void fun()
{
//Z z = new Z();//编译错误,不能创建对象
}
}

集合

注:点框的为接口、虚线框的为抽象类、实线框的为功能类(右下角的Collections为公用工具类,里面含有大量静态成员函数供集合使用)

集合只能容纳对象,不能容纳基本数据类型;元素通过实现Comparable接口、或提供一个实现Comparator接口的比较算法类来定义比较的规则。

List集合是有序集合(放入的顺序与存储的顺序一致),集合中的元素可以重复,访问集合中的元素可以根据元素的索引来访问。
Set集合是无序集合(放入的顺序与存储的顺序不一致),集合中的元素不可以重复,访问集合中的元素只能根据元素本身来访问。
Map集合中保存key-value对形式的元素,其key对象是不允许重复的(换个角度说:key对象的合集就是一个Set集合),访问时只能根据每项元素的key来访问其value;插入时如果key存在,则替换原来的value对象。

对象重复的含义:
(1) 两个对象e1和e2,如果e1.equals(e2)为true,则认为e1和e2重复,否则认为两个对象不重复
(2) 默认两个对象是否相等的equals方法是判断两个对象变量引用值是否指向同一个地址空间,我们可以重写equals方法来自定义重复的含义

ArrayList线程不安全;Vector线程安全(如果是单线程程序,推荐使用ArrayList)
ArrayList通过数组实现,LinkedList通过链表实现(不涉及到插入、删除等操作,推荐使用ArrayList)
HashSet相比,TreeSet会对容器内的元素进行排序;同理,相比HashMapTreeMap也会对容器内的元素进行排序
HashMap线程不安全,键与值都可以为null;Hashtable线程安全,键与值不能为null(如果是单线程程序,推荐使用HashMap)

/***** AppMain.java *****/
import java.util.*;
public class AppMain
{
public static void main(String[] args)
{
/* ArrayList */
List list = new ArrayList();
list.add(new Integer(1));
list.add("2");
list.add(new Short((short)3));
ListIterator iList = list.listIterator();
while(iList.hasNext())
{
System.out.println(iList.next());
} /* HashSet */
Set hSet = new HashSet();
hSet.add("1");
hSet.add(new Integer(2));
hSet.add("3");
Iterator iHSet = hSet.iterator();
while(iHSet.hasNext())
{
System.out.println(iHSet.next());
} /* TreeSet */
Set tSet = new TreeSet();
tSet.add("1");
//tSet.add(new Integer(2)); //运行时错误,TreeSet会对元素进行排序,因此需要实现插入元素间相互比较的Comparable接口
tSet.add("3");
Iterator iTSet = tSet.iterator();
while(iTSet.hasNext())
{
System.out.println(iTSet.next());
} /* HashMap */
HashMap hm = new HashMap();
hm.put(null, 0);
hm.put("1", null);
hm.put(new Integer(2), "2");
hm.put("3", new Float(3.0f));
Set sHm = hm.keySet();
Iterator iHm = sHm.iterator();
while(iHm.hasNext())
{
Object k = iHm.next();
Object v = hm.get(k);
System.out.println(k + "=" + v);
} /* Hashtable */
Hashtable ht = new Hashtable();
// ht.put(null, 0); //运行时错误
// ht.put("1", null); //运行时错误
ht.put(new Integer(2), "2");
ht.put("3", new Float(3.0f));
Enumeration e = ht.keys();
while(e.hasMoreElements())
{
Object k = e.nextElement();
Object v = ht.get(k);
System.out.println(k + "=" + v);
} /* TreeMap */
TreeMap tm = new TreeMap();
tm.put("1", new Long(1));
tm.put("2", new Double(2.0));
// tm.put(new Integer(3), "3"); //运行时错误,TreeMap会按照Key进行排序,因此Key需要实现插入元素间相互比较的Comparable接口
Set sTm = tm.keySet();
Iterator iTm = sTm.iterator();
while(iTm.hasNext())
{
Object k = iTm.next();
Object v = tm.get(k);
System.out.println(k + "=" + v);
}
}
}

以上的示例为非泛型实现的集合,现在已不推荐使用了。(由于使用集合中的元素时,必须进行造型操作,效率低;而且造型操作可能在程序运行时出现问题)

泛型实现的集合在定义容器时,同时定义容器中对象的类型,这就使得容器内的元素只能是该对象类型或其子对象类型。

泛型实现的集合拥有与非泛型实现的集合同样的特性,一致的外部接口。(ArrayList  LinkedList  HashSet  TreeSet  HashMap  TreeMap  Hashtable

/***** AppMain.java *****/
import java.util.*;
public class AppMain
{
public static void main(String[] args)
{
/* ArrayList */
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
list.add("3");
ListIterator<String> iList = list.listIterator();
while(iList.hasNext())
{
System.out.println(iList.next());
} /* HashSet */
Set<Integer> hSet = new HashSet<Integer>();
hSet.add(1);
hSet.add(new Integer(2));
hSet.add(new Integer(3));
Iterator<Integer> iHSet = hSet.iterator();
while(iHSet.hasNext())
{
System.out.println(iHSet.next());
} /* TreeSet */
Set<String> tSet = new TreeSet<String>();
tSet.add("1");
//tSet.add(new Integer(2)); //编译时错误
tSet.add("3");
Iterator<String> iTSet = tSet.iterator();
while(iTSet.hasNext())
{
System.out.println(iTSet.next());
} /* HashMap */
HashMap<String, Integer> hm = new HashMap<String, Integer>();
hm.put(null, 0);
hm.put("1", null);
hm.put("2", new Integer(2));
hm.put("3", new Integer(3));
Set<String> sHm = hm.keySet();
Iterator<String> iHm = sHm.iterator();
while(iHm.hasNext())
{
String k = iHm.next();
Integer v = hm.get(k);
System.out.println(k + "=" + v);
} /* Hashtable */
Hashtable<String, Integer> ht = new Hashtable<String, Integer>();
//ht.put(null, 0); //运行时错误
//ht.put("1", null); //运行时错误
ht.put("2", new Integer(2));
ht.put("3", 3);
Enumeration<String> e = ht.keys();
while(e.hasMoreElements())
{
String k = e.nextElement();
Integer v = ht.get(k);
System.out.println(k + "=" + v);
} /* TreeMap */
TreeMap<String, Integer> tm = new TreeMap<String, Integer>();
tm.put("1", 1);
tm.put("2", new Integer(2));
// tm.put(new Integer(3), 3); //编译时错误
Set<String> sTm = tm.keySet();
Iterator<String> iTm = sTm.iterator();
while(iTm.hasNext())
{
String k = iTm.next();
Integer v = tm.get(k);
System.out.println(k + "=" + v);
}
}
}

Java简明教程的更多相关文章

  1. Java 简明教程

    本文为 Java 的快速简明教程,主要用于快速了解.学习和复习java的语法特点. // 单行注释 /* 多行注释 */ /** JavaDoc(Java文档)注释是这样的.可以用来描述类和类的属性. ...

  2. Java简明教程 12.多线程(multithreading)

    单线程和多线程 关于它们的区别,zhihu上有一个回答,我认为十分不错,如下: . 单进程单线程:一个人在一个桌子上吃菜. . 单进程多线程:多个人在同一个桌子上一起吃菜. . 多进程单线程:多个人每 ...

  3. Java简明教程 11.异常

    异常的感性认识 在没有异常机制的语言中,经常通过返回值来表示调用该函数产生的各种问题(异常),比如c语言. divide.c #include <stdio.h> int main() { ...

  4. Java网络编程简明教程

    Java网络编程简明教程 网络编程  计算机网络相关概念 计算机网络是两台或更多的计算机组成的网络,同一网络内的任意两台计算机可以直接通信,所有计算机必须遵循同一种网络协议. 互联网 互联网是连接计算 ...

  5. Docker简明教程

    Docker简明教程 [编者的话]使用Docker来写代码更高效并能有效提升自己的技能.Docker能打包你的开发环境,消除包的依赖冲突,并通过集装箱式的应用来减少开发时间和学习时间. Docker作 ...

  6. Java8简明教程(转载)

    ImportNew注:有兴趣第一时间学习Java 8的Java开发者,欢迎围观<征集参与Java 8原创系列文章作者>. 以下是<Java 8简明教程>的正文. “Java并没 ...

  7. Lisp简明教程

    此教程是我花了一点时间和功夫整理出来的,希望能够帮到喜欢Lisp(Common Lisp)的朋友们.本人排版很烂还望多多海涵! <Lisp简明教程>PDF格式下载 <Lisp简明教程 ...

  8. appium简明教程

    appium简明教程 什么是appium? 下面这段介绍来自于appium的官网. Appium is an open-source tool you can use to automate mobi ...

  9. Tips & Tricks:Apache log4j简明教程(二)

    在上一讲Apache log4j简明教程(一)中介绍了log4j的基本概念,配置文件,以及将日志写入文件的方法,并给出了一个详细的示例.这一讲,我在继续谈一谈如何使用log4j将日志写入MySQL数据 ...

随机推荐

  1. Codeforces 727 D T-shirts Distribution

    Description 有 \(6\) 种尺码的衣服,有的人只适合 \(1\) 种衣服,有的人适合相邻的 \(2\) 种,问是否存在合法方案,并输出. Sol 贪心. 首先,只适合 \(1\) 种衣服 ...

  2. BZOJ 2084: [Poi2010]Antisymmetry

    Sol Manacher. \(O(n)\) Manacher很简单啊.改一改转移就可以了. 然后我WA了.一开始天真的认为id只会是奇数,然后就GG. 一组 Hack 数据 3 1 0 0 然后就跳 ...

  3. Shape + Selector: Make a Shape as one item of the Selector

    Generally, I use a selector to select pictures or colors to render the normal and the pressed backgr ...

  4. windows下C语言编程获取磁盘(分区)使用情况

    windows下编程获取磁盘(分区)使用情况 windows下编程获取磁盘(分区)使用情况 GetLogicalDriveStrings函数 使用示例 获取需要的缓冲区长度示例 获取所有驱动器号示例 ...

  5. Python统计百分比及排序

    source.txt: 60行 89 91 93 90 92 92 94 92 89 95 93 92 90 92 93 94 94 92 90 92 92 92 ... 统计各个值的百分比,并排序 ...

  6. Iterator中hasNext(), next() 和ResultSet结果集的next方法的区别

    接口 Iterator专门的迭代输出接口,将元素一个个进行判断,用hasNext() 判断是否有值,用next()方法把元素取出.hasNext() 如果仍有元素可以迭代,则返回 true.next( ...

  7. Game of Life I & II

    According to the Wikipedia's article: "The Game of Life, also known simply as Life, is a cellul ...

  8. document.documentElement.scrollTop || document.body.scrollTop

    如果有doctype的声明,需要用document.documentElement.scrollTop没有doctype的声明,用document.body.scrollTop

  9. 【leetcode】Search a 2D Matrix

    Search a 2D Matrix Write an efficient algorithm that searches for a value in an m x n matrix. This m ...

  10. js中修改标签的hidden属性

    hidden属性在html5中,只要存在,就是隐藏效果,而不论值为多少 要显示元素,要删除hidden属性,而不是设置为false <script type="text/javascr ...