1、switch
与c++不同,java的switch不能判断long类型,但可以是String类型或Integer这种基本类型包装器类型,与C++相同的是也不能是浮点型。
2、局部变量、引用类型
java中有基本类型(int、boolean等)和类类型两种类型,类类型又称为引用类型。java中的基本类型、类类型在定义后必须初始化,否则不能被使用,因为在初始化的时候系统才为它分配内存,所以不存在局部类对象,所有的类对象都是new出来后使用。类中的成员变量在对象分配内存后会自动进行初始化,数值类元素会初始化为0、boolean类型为false、引用类型为null。java中的局部变量不能是static类型,所以静态变量只能是静态成员变量,java中通过类名来引用静态成员变量与C++不太相同,如C++中为MyClass::staticNum,Java中为MyClass.staticNum,静态方法中只能引用静态成员方法和静态成员变量。
int a; //int a = 0;
if(a > 0) //报错
...;
String str; //应该为String str = ""; String str = null;
System.out.println(str); //报错
TestClass t; //应该为TestClass t = new TestClass(); TestClass t = null;
System.out.println(t.getClass()); //报错(getClass为Object中输出类名的方法)
TestClass tt = Objects.requireNonNull(t); //检测t是否为null,为null的话会抛出NullPointerException异常
Objects.requireNonNull(t, "bar must not be null"); //定制抛出的NullPointerException异常
new TestClass().getClass(); //匿名对象的使用,适合只使用一次对象的情况
引用类型包括数组、对象、接口,与基本类型变量一样,引用变量在定义后必须进行初始化,可以直接将引用变量初始化为null。定义相当于是定义了一个指针,该指针存放了内存分配的地址,赋值初始化的时候为该对象在堆上分配空间。复制该引用变量仅是增加了一个指向相同内存的引用变量,当所有指向该内存的引用变量释放(生命期或作用域到了尽头)后,即该内存没有任何引用变量指向它的时候,该内存会被垃圾回收机制回收:
class Mem
{
public int num = 10;
public void SetNum(int num){this.num = num;}
}
public class Test
{
String name;
Mem data;
public Test(String str, Mem d)
{
name = str;
data = d;
}
public static void main(String[] args)
{
String str = "c++"; //引用变量可以使用常量来初始化
Mem m = new Mem(); //引用变量也可以使用new来初始化
Test t = new Test(str, m);
System.out.println(t.name); //输出为c++
System.out.println(t.data.num); //10
str = "java"; //str指向其它内存,它原来指向的内存还有
m.SetNum(50);
System.out.println(t.name); //输出为c++
System.out.println(t.data.num); //输出为50
}
}
java中int、double等基本数据类型变量与c++相同,引用类型变量则类似于c++中的指针,而对其赋值初始化的话相当于让其指向新的内存地址,java中参数传递只有值传递:
public class Foo
{
static void func(int num, String str, int[] ary)
{
num = 50; //基本类型是值传递,所以该行不会改变实参值
str = "changed?"; //对象类型相当于是C++中指针,对其使用等号赋值的话也不会改变实参的值
ary[0] = 0;
}
public static void main(String[] args)
{
int i = 10;
String str = "test";
int[] ary = {1, 2, 3};
func(i, str, ary);
System.out.println(i + str + ary[0]); //输出为10test0
}
}
不定长度自变量(可变长参数、不定参数)是编译程序蜜糖,它其实就是一个数组,使用它的话必须是参数列表中的最后一个:
class Test{
void display(String...ary)
{
for(String item:ary)
{
System.out.println(item);
}
}
}
public class Main {
public static void main(String[] args){
Test t = new Test();
t.display(new String("c++"));
t.display(new String("c++"), new String("java"));
String[] ary = new String[]{"c++", "java", "c#"};
t.display(ary);
}
}
对于String的改变不会影响到原对象,因为这些操作实际上都是生成新的String对象,所以如果对于String对象会进行大量修改操作的话不推荐使用。StringBuffer和StringBuilder则是对本对象的改变,但StringBuffer是线程安全的,StringBuilder不是线程安全的。
3、数组
数组也是对象,属于引用类型,使用它之前需要定义+分配内存两步,如果分配内存的时候不显示初始化数组则自动会将数值类元素初始化为0、boolean类型为false、引用类型为null,与C++不同的是定义的时候 [] 紧邻类型之后而不是数组名之后:
int[] ary1; //定义
ary1 = new int[10]; //分配内存
int[] ary2 = new int[5]; //定义+分配内存
int[] ary3 = {1, 2, 3}; //定义+分配内存+初始化
for(int item : ary3)
{
System.out.println(item);
}
ary3 = new int[]{1, 2, 3, 4, 5};
for(int item : ary3)
{
System.out.println(item);
}
int[] ary5 = new int[]{0, 1, 2, 3, 4 };//定义+分配内存+初始化,注意此时不应再指定大小
String[] clrAry = {new String("red"), new String("blue")}; //对象数组
String[] ary6 = new String[10];
for(int i = 0; i < ary6.length; ++i)
{
System.out.println(ary6[i]);
}
Object[] ary7 = new String[]{"c", "c++", "java", null}; //对象数组,元素可以是子类对象
for(Object item:ary7) //for each循环
{
System.out.println(item);
}
int[] scores1 = {1, 2, 3};
int[] scores2 = scores1;
scores2[0] = 1;
System.out.println(scores1[0]); //输出为1
int[] array1 = new int[5];
int[] array2 = new int[10];
int[] array3 = array1;
array1 = array2;
array3 = array2;
//原array1指向的堆内存已无任何引用指向它,其会被垃圾回收机制自动回收
int[] ary8 = new int[5];
int[] ary9 = new int[]{0, 1, 2, 3, 4};
for(int item:ary8) //输出为0, 0, 0, 0, 0
{
System.out.println(item);
}
System.arraycopy(ary9, 0, ary8, 0, 5); //复制一个数组中元素到另一个数组
for(int item:ary8) //输出为0, 1, 2, 3, 4
{
System.out.println(item);
}
数组的元素类型也可以是数组,这就类似于二维数组,而对其可以当做一维数组来处理:
int[][] ary; //ary是一个数组,其元素类型是int[]即一个int类型数组
ary = new int[3][]; //ary大小为3
ary[0] = new int[5]; //因为ary的第一个元素ary[0]也是数组,所以为其申请内存
ary[0][2] = 1;
for(int item:ary[0])//输出为0, 0, 1, 0, 0
{
System.out.println(item);
}
int[][] arr = {{1, 2, 3}, {4, 5, 6}};
for(int[] row : arr) //遍历二维数组
{
for(int value : row)
{
System.err.println(value);
}
}
以下代码实际上一个Integer或String实例都没有建立,因为对于引用类型不显示初始化的话会将其引用值设为null:
Integer[] ary1 = new Integer[3];
String[] ary2 = new String[3];
Integer[][] ary3 = new Integer[2][3];
数组的复制:
int[] ary1 = {1, 2, 3};
int[] ary2 = ary1; //仅是复制引用,ary2与ary1共用一个对象
int[] ary3 = java.util.Arrays.copyOf(ary1, ary1.length); //复制整个数组数据,ary3与ary1引用的是两个对象
/*class Clothes{
Clothes(String color, char size){
m_color = color;
m_size = size;
}
String m_color;
char m_size;
}*/
Clothes[] c1 = {new Clothes("red", 'L'), new Clothes("blue", 'M')};
Clothes[] c2 = new Clothes[c1.length];
for(int i = 0; i < c1.length; ++i)
c2[i] = c1[i]; //浅复制
c1[0].m_color = "yellow";
System.out.println(c2[0].m_color); //输出 yellow
Clothes[] c3 = {new Clothes("red", 'L'), new Clothes("blue", 'M')};
Clothes[] c4 = new Clothes[c1.length];
for(int i = 0; i < c1.length; ++i)
c4[i] = new Clothes(c3[i].m_color, c3[i].m_size); //深复制
c3[0].m_color = "yellow";
System.out.println(c4[0].m_color); //输出 red
工具类Arrays中包含了一系列操作数组的静态方法,如对数组元素赋予指定值fill、查找binarySearch、排序sort、复制copyOf、转换为字符串toString、转换为List的asList等。System类里也包含一个从指定数组复制元素到另一个数组的功能函数arraycopy()。另外java8还对Arrays新增了一系列可以利用多核CPU来提高性能的函数,如给数组排序的parallelSort(要排序的数组可以是基本类型或对象类型,如果是对象的话对象必须操作Comparable或者使用指定的Comparable)、使用指定方法给元素赋值的parallelPrefix、parallelSetAll等:
int[] arys = {1, 2, 3, 4, 5};
//Arrays.parallelPrefix(arys, (left/*上次运算的返回值*/, right/*当前元素*/)->left + right); //使用指定方法对元素赋新值
//System.out.println(Arrays.toString(arys)); //输出为 [1, 3, 6, 10, 15]
Arrays.parallelSetAll(arys, idx/*元素索引*/-> (idx + 1) * 10); ///使用指定方法对元素赋新值
System.out.println(Arrays.toString(arys)); //[10, 20, 30, 40, 50]
4、JVM垃圾收集机制(GC,Garbage Collection)
public class Some{
Some next;
}
Some s1 = new Some();
Some s2 = new Some();
s1 = s2; //原s1参考的对象变为内存中的垃圾,会被垃圾回收机制回收
Some s = new Some();
s.next = new Some();
s = null; //两个对象都被回收
Some[] somes = {new Some(), new Some(), new Some()};
somes = null; //四个对象被回收
Some some = new Some();
some.next = new Some();
some.next.next = new Some();
some.next.next.next = some;
some = null; //三个对象被回收,如下图所示
5、访问权限
Java中类的成员前面的public、protected、private与c++中意义类似,并且多了一个default即不加修饰符的情况:public为可以被外部类访问,protected为可以被子类访问,private为只能被当前类访问,default为可以被相同包中外部类访问。public与default还可以修饰类:public为可以被外部类访问,default为可以被相同包中外部类访问。
如下两个public类,他们在同一目录下,可以互相访问:
//Hello.java
public class Hello
{
public static void main(String[] args)
{
HelloWorld hw = new HelloWorld();
hw.Print();
}
public void Print()
{
System.out.println("Hello");
}
}
//HelloWorld.java
public class HelloWorld
{
public static void main(String[] args)
{
Hello h = new Hello();
h.Print();
}
public void Print()
{
System.out.println("Hello World");
}
}
6、数据成员初始化
类中数据成员如果没有指定初始值的话会使用默认的值进行初始化,如int类型被初始化为0,char为\u0000,boolean为false,类类型为null。
7、GUI
Java使用AWT和Swing类库来完成GUI开发:
package xu;
import java.awt.*;
import javax.swing.*;
public class Test
{
public static void main(String[] args)
{
//使用AWT
/*Frame f = new Frame("测试窗口"); //窗口
Panel p = new Panel(); //容器:盛装其它组件,不能单独存在,必须放置到其它容器中,使用默认的布局管理器
p.add(new TextField(20)); //编辑框
p.add(new Button("按钮")); //按钮
f.add(p);
f.setBounds(500, 300, 250, 200);
f.setVisible(true);*/
//使用Swing
JFrame f = new JFrame();
JPanel p = new JPanel();
p.add(new JTextField(20));
p.add(new JButton("按钮"));
f.add(p);
f.setBounds(500, 300, 250, 200);
f.setVisible(true);
}
}