Java是完全面向对象的语言,相比较C和C++而言,语法上是极为相似的,注释方式也相同。在Java中所有函数和变量部必须是类的一部分。除了基本数据类型之外,其他的数据对Java来说都是对象。
编译与运行
Java运行环境需要安装jdk并设置环境变量
编译命令:javac
$javac HelloWorld.java
//当前路径下,将有一个名为HelloWorld.class的文件生成。
运行命令:java
$java HelloWorld
//注意运行文件没有后缀
变量类型
Java中的变量类型如下:
类型 | 存储大小 |
---|---|
byte | 1byte |
int | 4bytes |
short | 2bytes |
long | 8bytes |
float | 4bytes |
double | 8bytes |
char | 2bytes |
boolean | 1bit |
基本类型的数据成员的默认初始值:
int: 0
boolean: false
other type: null
数组
声明一个数组的3种方式:(以int数组为例)
int[] a;
int[] a = new int[100];
int[] a = new int[] {1, 2, 3, 4, 5};
Class
定义类的语法:
//ClassName.java
class ClassName
{
public ClassName();//构造函数
public member;
private func();
public static void main(String[] args) {
}
}
文件名必须与最顶层的类名相同且大小写敏感。
this在类中指代对象自身,函数重载与C++类似。
main函数声明作为静态成员函数,程序执行时会自动调用存在main函数成员的类作为程序入口。
Java同样通过三个关键字来控制对象的visibility: public, private, protected。
interface
以Move为例,定义一个Move的接口:
interface Move {
void fly();
void run();
}
A这个interface中定义了两个方法的原型(stereotype): fly()和run()。
一个方法的原型规定了方法名,参数列表和返回类型。原型可以告诉外部如何使用这些方法。
在interface中,不需要定义方法的主体,不需要说明方法的可见性.
注意第二点,interface中的方法默认为public,一个类的public方法构成了接口,所有出现在interface中的方法都默认为public。
一个类可以同时实现多个接口用,分隔开
class Amove implements Move
{
public void fly()
{
System.out.println("fly in the sky");
}
public void run()
{
System.out.println("run through the city");
}
}
class Bmove implements Move
{
public void fly()
{
System.out.println("fly in the space");
}
public void run()
{
System.out.println("run through the street");
}
}
继承
用extends关键字表示继承
接口同样适用于继承
由于在创建衍生对象的时候,基类对象先被创建和初始化,所以,基类的构造方法应该先被调用。
可以使用super(argument list)的语句,来调用基类的构造方法。
重写与protected机制与C++类似。
抽象类(abstract class)的语法,用于说明类及其方法的抽象性,继承的子类必须实现抽象类中声明为abstract 的方法
package
1.包的建立
package com.lyq.test;
public class Test
{
/**
* constructor
*/
public Test()
{
System.out.println("gg");
}
}
上面的第一行语句
package com.lyq.test;
表示该程序在com.lyq.test包中。com.lyq(lyq.com的反写)表示包作者的域名 。Java要求包要有域名前缀,以便区分不同作者。
包为Java程序提供了一个命名空间(name space)。一个Java类的完整路径由它的包和类名共同构成,比如com.lyq.test.Test。相应的Test.java程序要放在com/lyq/test/下。类是由完整的路径识别的,所以不同的包中可以有同名的类。
一个类没有public关键字,它实际上表示一种默认权限: 该类在它所在的包中可见。
同样,对象的成员也可以是默认权限(包中可见)。
2.包的调用
如果整个包(也就是com文件夹)位于当前的工作路径中,可以直接使用包。
import com.lyq.test.*;
如果包没有放在当前工作路径下,编译运行时需要加上-classpath参数说明包所在的文件夹路径,比如:
$javac -classpath /home/lyq/javapackage:. Test.java
$java -classpath /home/lyq/javapackage:. Test
就是从/home/lyq/javapackage和工作路径(.)中寻找包。
Class类的方法
Class对象记录了相应类的信息,比如类的名字,类所在的包
getName() //返回类的名字
getPackage() //返回类所在的包
getFields() //返回所有的public数据成员
getMethods() //返回所有的public方法
可以利用Class对象的newInstance()方法来创建相应类的对象,比如:
A b = a.newInstance();
newInstance()调用默认的不含参数的构建方法。
final
final关键字的基本含义是: 这个数据/方法/类不能被改变了。
final基本类型的数据: 定值 (constant value),只能赋值一次,不能再被修改。
final方法: 该方法不能被覆盖。private的方法默认为final的方法。
final类: 该类不能被继承。
static
类方法声明为static的方法代表了类可以实现的动作,其中的操作不涉及某个具体对象。如果一个方法声明为static,那么它只能调用static的数据和方法,而不能调用非static的数据和方法。类似于全局变量共享于同一个类。
引用
由于Java将指针的概念隐藏,因此引用都是通过赋值来指向一个对象。
ClassA a = new ClassA();
b = a;
new是在内存中为对象开辟空间。
a指代一个ClassA对象,被称为对象引用(reference)。a并不是对象本身,而是类似于一个指向对象的指针。a存在于内存的栈(stack)中。用等号赋值时,是将new在堆中创建对象的地址赋予给对象引用。
这里的内存,指的是JVM (Java Virtual Machine)虚拟出来的Java进程内存空间。
b是对a指向对象的浅复制。
参数传递
Java的参数传递为值传递。
基本类型变量的值传递,意味着变量本身被复制,并传递给Java方法。Java方法对变量的修改不会影响到原变量。
引用的值传递,意味着对象的地址被复制,并传递给Java方法。Java方法根据该引用的访问将会影响对象。
JVM垃圾回收
在Java中,对象的是通过引用使用的。如果不再有引用指向对象,那么我们就再也无从调用或者处理该对象。这样的对象将不可到达(unreachable)。垃圾回收用于释放不可到达对象所占据的内存。这是垃圾回收的基本原则。
因此,我们以栈和static数据为根(root),从根出发,跟随所有的引用,就可以找到所有的可到达对象。也就是说,一个可到达对象,一定被根引用,或者被其他可到达对象引用。
JVM的垃圾回收是多种机制的混合。JVM会根据程序运行状况,自行决定采用哪种垃圾回收。
“mark and sweep”。这种机制下,每个对象将有标记信息,用于表示该对象是否可到达。当垃圾回收启动时,Java程序暂停运行。JVM从根出发,找到所有的可到达对象,并标记(mark)。随后,JVM需要扫描整个堆,找到剩余的对象,并清空这些对象所占据的内存。
“copy and sweep”。这种机制下,堆被分为两个区域。对象总存活于两个区域中的一个。当垃圾回收启动时,Java程序暂停运行。JVM从根出发,找到可到达对象,将可到达对象复制到空白区域中并紧密排列,修改由于对象移动所造成的引用地址的变化。最后,直接清空对象原先存活的整个区域,使其成为新的空白区域。
上面两种机制是通过分代回收(generational collection)混合在一起的。每个对象记录有它的世代(generation)信息。所谓的世代,是指该对象所经历的垃圾回收的次数。世代越久远的对象,在内存中存活的时间越久。
异常处理
异常的类型
Java中的异常类都继承自Trowable类。一个Throwable类的对象都可以抛出(throw)。
Throwable对象可以分为两组。一组是unchecked异常,异常处理机制往往不用于这组异常,包括:
- Error类通常是指Java的内部错误以及如资源耗尽的错误。当Error(及其衍生类)发生时,我们不能在编程层面上解决Error,所以应该直接退出程序。
- Exception类有特殊的一个衍生类RuntimeException。RuntimeException(及其衍生类)是Java程序自身造成的,也就是说,由于程序员在编程时犯错。RuntimeException完全可以通过修正Java程序避免。比如将一个类型的对象转换成没有继承关系的另一个类型,即ClassCastException。这类异常应该并且可以避免。
剩下的是checked异常。这些类是由编程与环境互动造成程序在运行时出错。比如读取文件时,由于文件本身有错误,发生IOException。再比如网络服务器临时更改URL指向,造成MalformedURLException。异常处理机制主要是用于处理这样的异常。
自定义异常
我们可以通过继承来创建新的异常类。在继承时,我们往往需要重写构造方法。异常有两个构造方法,一个没有参数,一个有一个String参数。比如:
class MyException extends Exception
{
public MyException() {}
public MyException(String msg) {
super(msg);
}
}