主要内容:
包
类的说明符
方法的说明符
对象的销毁
接口
内部类和匿名内部类
异常处理
1、包(package)
为了便于管理大型软件系统中数目众多的类,解决类命名冲突的问题,java引入了包。
package必须是文件中的第一条语句,也就是说,在package语句之前,除了空白和注释之外不能有其他语句。
如果不加package语句,则指定为缺省包或无名包。
包对应着文件系统的目录层次结构。
在package语句中,用“.”来指明包(目录)的层次。
2、编译并生成包
在当前目录下生成包
javac -d . Test.java
在指定目录下生成包
javac -d E:JavaLesson Test.java
编译某一目录下所有java文件,此时不用当心编译次序
javac *.java
设置了环境变量之后,会默认在环境变量指定的目录下搜索类。
set classpath=%classpath%;d:java\;
3、import语句
引入包中的类
import java.io.File;
引入整个包
import java.io.*;
在同一包中的类可以相互引用,无需import语句。
java.lang包是默认导入的,编写程序时,无需显示导入。
没有导入相应包时,必须在调用类时写上类的全名。
4、类的说明符
1>类的访问说明符
public
default(不加访问说明符时)
2>类的其他修饰符
final
abstract
5、方法的说明符
1>方法的访问说明符
public
protected
default(不加访问说明符时)
private
2>方法的其他修饰符
static
final
abstract
native
synchronized
6、方法的访问控制
public protected default private
同类 yes yes yes yes
同包 yes yes yes
子类 yes yes
通用 yes
7、final方法
为了确保某个函数的行为在继承过程中保持不变,并且不能呗覆盖,可以使用final方法。
为了效率上的考虑,将方法声明为final,让编译器对此方法的调用进行优化。要注意的是:编译器会自动对final方法进行判断,并决定是否进行优化。通常在方法的体积很小,而我们确实不希望它被覆盖时,才将它声明为final。
class中所有的private和static方法自然就是final。
8、抽象方法和抽象类
在类中没有方法体的方法,就是抽象方法。
含有抽象方法的类,即位抽象类。
如果一个子类没有实现抽象基类中所有的抽象方法,则子类也成为一个抽象类。
抽象类不能实例化。
我们可以将一个没有任何抽象方法的类声明为abstract,避免有这个类产生任何的对象。
构造方法,静态方法,私有方法,final方法不能被声明为抽象的方法。
9、native方法
native方法是用户在java中可以使用,但不能编写的方法。
JNI(Java Native Interface),它允许java虚拟机(JVM)内部运行的java代码能够与其他编程语言(如C,C++,汇编语言)编写的应用程序和库进行互操作。
JNI最大的好处是它没有对底层java虚拟机的实现施加任何限制,因此,java虚拟机厂商可以在不影响虚拟机其他部分的情况下添加对JNI的支持。程序员只需编写一种版本的本地应用程序和库,就能够与所有支持JNI的java虚拟机协同工作。
JNI可以理解为java和本地应用程序之间的中介。
书写步骤:
·编写带有native声明的方法的java类
·使用javac命令编译所编写的java类 JNI
·使用javah -jni java类名生成扩展名为h的头文件
·使用C/C++实现本地方法
·将C/C++编写的文件生成动态连接库
·使用java命令运行java类
10、垃圾回收机制
垃圾回收是一个低优先级的线程在后台自动运行。
System.gc()用来显示调用垃圾回收方法finalize()。
11、接口
实现接口采用关键字implements。
接口中所有方法默认都是public abstract。
接口中数据成员默认都是public static final。
在接口中声明方法时,不能使用native、static、final、synchronized、private、protected等修饰符。
和public类一样,public接口也必须定义在与接口同名的文件中。
实现一个接口时,如果不能实现其中所有方法,必须将类定义为抽象类。
一个接口可以继承自另一个或多个接口。
java中不允许类的多继承,但允许接口的多继承。
interface Sittable
{
void sit();
}
interface Lie
{
void sleep();
}
interface Chair extends Sittable
{
}
interface Sofa extends Sittable, Lie //一个接口继承多个接口
{
}
class Sofa1 implements Sittable, Lie //一个类实现多个接口
{
public void sit()
{
}
public void sleep()
{
}
}
interface HealthCare
{
void massage();
}
class Chair implements Sittable
{
public void sit(){};
}
class Sofa extends Chair implements Lie, HealthCare //在继承类的同时,实现多个接口
{
public void sleep(){};
public void massage(){};
}
12、内部类
在一个类中定义另外一个类,这个类就叫内部类或内置类。
内部类可以将逻辑上相关的一组类组织起来,并有外部类来控制内部类的可见性。
当我们建立一个内部类时,其对象就拥有了与外部类对象之间的一种关系,这是通过一个特殊的this引用形成的,使得内部类对象可以随意访问外部类中所有成员。
内部类访问外部类时,须使用Outer.this.变量。
在方法中定义的内部类,如果要访问方法中定义的本地变量或方法的参数,则变量必须声明为final。
内部类可以声明为private和protected,还可以声明为abstract和final。
内部类可以声明为static,但此时不能再使用外部类的非static成员变量和非static的成员方法。
非static的内部类中的成员不能声明为static的,只有在顶层类或static的内部类中才可声明static成员。
其他类访问某外部类的非静态内部类时,应该使用new Outer().new Inner();
为什么使用内部类?
1>在内部类中,可以随意的访问外部类的成员,可以更好的组织管理我们的代码,增强代码的可读性。
2>内部类可以用于创建适配器类,适配器类是用于实现接口的类,使用内部类来实现接口,可以更好的定位与接口关联的方法在代码中的位置。
3>内部类的更多用法。
例子程序:
class Outer{
private int index=100;
void print() {
Inner i=new Inner();
i.print();
}
void fn(final int a)
{
final int b=0;
if(true)
{
class Inner{
void print(){
int index=30;
System.out.println(index); //输出30
System.out.println(Outer.this.index); //输出100
System.out.println(a);
System.out.println(b);
}
}
}
}
}
class Test{
public static void main(String[] args){
Outer o=new Outer();
o.print();
Outer.Inner inner=outer.new Inner();
}
}
class Car
{
class Wheel
{
}
}
class PlaneWheel extends Car.Wheel
{
PlaneWheel(Car car)
{
car.super(); //通过super.car(),建立一个内部类对象到外部类对象的引用关系
}
public static void main(String[] args)
{
Car car = new Car();
PlaneWheel pw = new PlaneWheel(car);
}
}
interface Animal
{
void eat();
void sleep();
}
class Zoo
{
private class Tiger implements Animal //私有内部类实现接口,隐藏实现细节
{
public void eat()
{
System.out.println("tiger eat");
}
public void sleep()
{
System.out.println("tiger sleep");
}
Animal getTiger()
{
return new Tiger();
}
Animal getAnimal()
{
return new Animal() //匿名内部类
{
public void eat()
{
System.out.println("animal eat");
}
public void sleep()
{
System.out.println("animal sleep");
}
};
}
}
}
class Test
{
public static void main(String[] args)
{
Zoo z=new Zoo();
Animal tiger=z.getTiger();
tiger.eat(); //输出tiger eat
tiger.sleep(); //输出tiger sleep
Animal animal=z.getAnimal();
animal.eat(); //输出animal eat
animal.sleep(); //输出animal sleep
}
}
内部类解决接口和父类中的相同方法表示的意义不同的问题,解决和C++中多继承相似的问题。
Machine.java:
interface Machine
{
void run();
}
class Person
{
void run()
{
System.out.println("run");
}
}
class Robot extends Person
{
private class MachineHeart implements Machine
{
public void run()
{
System.out.println("heart run");
}
}
Machine getMachine()
{
return new MachineHeart();
}
}
class Test
{
public static void main(String[] args)
{
Robot robot=new Robot();
Machine machine=robot.getMachine();
machine.run(); //输出heart run
robot.run(); //输出run
}
}
A.java:
class A
{
voidn fn1()
{
}
}
abstract class B
{
abstract void fn2();
}
class C extends A
{
B getB()
{
return new B()
{
public void fn2();
};
}
}
class Test
{
static void method1(A a)
{
a.fn1();
}
static void method2(B b)
{
b.fn2();
}
public static void main(String[] args)
{
C c=new C();
method1(c);
method2(c.getB());
}
}
13、异常类
1>异常处理
打开一个不存在的文件、网络连接中断、数组下标越界、正在加载的类文件丢失等都会引发异常。
java中的异常类定义了程序中遇到的轻微的错误条件。
java中的错误类定义了程序中不能恢复的严重错误条件。如内存溢出、类文件格式错误等。这一类错误由java运行系统处理,不需要我们去处理。
java程序在执行过程中如出现异常,会自动生成一个异常类对象,该异常对象将被提交给java运行时系统,这个过程称为抛出(throw)异常。
当java运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程称为捕获(catch)异常。
如果java运行时系统找不到可以捕获异常的方法,则运行时系统将终止,相应的java程序将退出。
异常处理语句:try/catch/finally语句。
对于运行时异常(RuntimeException),通常不需要我们去捕获,这类异常由java运行系统自动抛出并自动处理。
如果父类中的方法抛出多个异常,则子类中的覆盖方法要么抛出相同的异常,要么抛出异常的子类,但不能抛出新的异常(构造方法除外,因为构造方法不能被继承)。
我们可以在方法声明时,声明一个不会抛出的异常,java编译器就会强迫方法的使用者对异常进行处理。这种方式通常应用于abstract base class和interface中(目前没有异常,以后可能增加代码产生异常)。
Excep.java:
class Excep
{
Excep() throws ArithmeticException
{
}
public int division1(int a, int b) throws ArithmeticException
{
return a/b;
}
public int division2(int a, int b) throws Exception
{
return a/b;
}
catch(ArithmeticException e)
{
e.printStackTrace();
throw new Exception("can't divide by zero");
}
public int division3(int a, int b) throws ArithmeticException,DivisorIsMinusException
{
if(b<0)
{
throw new DivisorIsMinusException("divisor can't be minus");
}
return a/b;
}
public int fn1(int a, int b) throws Exception // 抛出异常
{
return division1(a,b);
}
}
class ChildExcep extends Excep
{
ChildExcep throws FileNotFoundException //可以抛出与父类构造方法不同的异常,因为构造方法不被继承
{
}
public int division3(int a, int b) throws ArithmeticException,DivisorIsMinusException //只能抛出与父类方法相同的异常或其子类异常
{
return a/b;
}
}
class DivisorIsMinusException extends Exception
{
DivisorIsMinusException(String str)
{
super(str);
}
}
class ExcepTest
{
public static int method1(Excep excep)
{
try
{
return excep.division3(5,0);
}
catch(ArithmeticException e)
{
System.out.println(e.toString());
}
catch(DivisorIsMinusException ex)
{
System.out.println(ex.toString);
}
return 0;
}
public static void main(String[] main)
{
ChildExcep ce=new ChildExcep();
method1(ce);
Excep excep=new Excep();
try
{
//excep.division1(5,0); //如果未捕获异常将抛出ArithmeticException,程序终止;如果捕获异常,则跳转到catch语句中继续执行
excep.fn1(5,0);
System.out.println("exception"); //此条语句得不到执行
}
catch(ArithmeticException e)
{
System.out.println("can't divide by zero");
//System.out.println(e.getMessage()); //输出:/ by zero
//System.out.println(e.toString()); //输出:java.lang.ArithmeticException:/ by zero,比e.getMessage()详细
//e.printStackTrace(); //输出:java.lang.ArithmeticException:/ by zero及错误所在位置,如果没有捕获异常,jvm会调用此方法打印错误信息
//System.exit(-1); //finally中语句不被执行
}
catch(Exception e) //所有异常都是Exception派生出来的,所以先捕获特殊异常,再捕获一般异常,以免发生重复捕获错误
{
e.printStackTrace();
}
finally
{
System.out.println("finally"); //任何情况下都会执行,即使try或catch中包含return语句,通常用来关闭数据库连接及释放资源。
}
System.out.println("finish");
}
}
输出:
can't divide by zero
finally
finish
14、java编程规范
1>package的命名
package的名字由全部小写的字母组成,例如:cn.com.mybole。
2>class和interface的命名 class和interface的名字由大写字母开头而其他字母都小写的单词组成,例如:Person,RuntimeException。
3>class变量的命名 变量的名字用一个小写字母开头,后面的单词用大写字母开头,例如:index,currentImage。
4>class方法的命名
方法的名字用一个小写字母开头,后面的单词用大写字母开头,例如:run(),getBalance()。
4>static final变量的命名 static final变量的名字所有字母都大写,并且能表示完整含义。例如:PI,PASSWORD。
5>参数的命名 参数的名字和变量的命名规范一致。
6>数组的命名 数组应该总是用这样的方式来命名:byte[] buffer。