1. Java语言的优点
1)
Java为纯面向对象语言。万物皆对象。2)
平台无关性。Java语言可以“一次编译,到处运行。”由于Java为解释性语言,编译器会把Java代码变成“中间代码”,然后在JVM上解释这都行。因此Java可以很好的跨平台执行,具有很好的可移植性。3)
Java提供了很多内置的类库,通过这些类库,简化了开发人员的程序设计工作,缩短了项目的开发时间。例如,Java提供了对多线程的支持,提供了垃圾回收器。4) 提供了对Web应用开发的支持。
5) 具有很好的安全性和健壮性。Java的强类型机制、垃圾回收器、异常处理和安全检查机制使得Java编写的程序有很好的健壮性。
6) 去除了C++中难以理解、容易混淆的特性,如头文件、指针、结构、多重继承等,使得程序更加严谨、简洁。
2. Java和C++的异同
Java与C++都是面向对象语言,都使用了面向对象思想(例如封装、继承、多态等),由于面向对象由许多非常好的特性(继承、组合等),因此两者都有很好的复用性。
1) Java为解释型语言,其运行过程为:程序源代码经过Java编译器编译成字节码,然后由JVM解释执行。而C/C++为编译型语言,源代码经过编译和链接后生成可执行的二进制代码。因为,Java的执行速度比C/C++慢,但是Java能够跨平台执行,而C/C++不能。
2) Java为纯面向对象语言,所有代码(包括函数、变量等)必须在类中实现,除了基本数据类型外,所有类型都是类。此外,Java不存在全局变量或全局函数。
3) Java去除了指针的概念,这有效防止了C/C++语言中操作指针可能引起的系统问题,从而使程序更安全。
4) Java不支持多重继承,在Java中使用接口来实现多重继承的目的,接口也具有多态特性。
5) C++中需要开发人员去管理对内存的分配,而Java提供了垃圾管理器来实现垃圾的自动回收,也不需要程序显示地管理内存的分配。
3. main()方法
publi cstatic void main(String[] args)为Java程序的入口方法,JVM在运行程序时,先查找main()方法。
1) mian()方法中必须有public和static修饰。方法中返回值为void,args为参数输出。
2) 可用final或synchronized来修饰main()方法,而且public和static没有先后顺序关系。如static public void main(String[] args)也合理
4. Java程序初始化的顺序
在Java语言中,当实例化对象时,对象所在类的所有成员变量首先要进行初始化,只有所有类成员完成初始化后,才会调用对象所在类的构造函数创建对象。
Java程序的初始化一般遵循3个原则(优先级依次递减):
①静态对象(变量)优先于非静态对象(变量)初始化,其中,静态对象(变量)只初始化一次。
②父类优先于子类进行初始化。
③按照成员变量的定义顺序进行初始化,即使变量定义散步于方法定义之中,它们依然在任何方法(包括构造函数)被调用之前先初始化。
初始化顺序:
父类静态变量>父类静态代码块>子类静态变量>子类静态代码块>父类非静态变量>父类非静态代码块>父类构造函数>子类非静态变量>子类非静态代码块>子类构造函数
5. Java的作用域
在Java中,变量的类型主要有3中:成员变量、静态变量、和局部变量。
1)类的成员变量的作用范围与类的实例化对象的作用范围相同,当类被实例化时,成员变量就会在内存中分配空间并初始化,直到这个被实例化对象的生命周期结束时,成员变量的生命周期才结束。
2) 被static修饰的成员变量被称为静态变量或全局变量,与成员变量不同的是,静态变量不依赖于特定的实例,而是被所有实例所共享,也就是说,只要一个类被加载,JVM就会给类的静态变量分配空间。因此,可以通过类名和变量名来访问静态变量。
3) 局部变量的作用域与可见性为它所在的花括号内。
成员变量的作用域
作用域与可见性 |
当前类 |
用一package |
子类 |
其他package |
public |
√ |
√ |
√ |
√ |
private |
√ |
× |
× |
× |
protected |
√ |
√ |
√ |
× |
default |
√ |
√ |
× |
× |
①public。表明该成员变量或方法对所有类或对象都是可见的,所有类或对象都可以直接访问。
②private。表明该成员变量或方法是私有的,只有当前类对其具有访问权限,除此之外的其他类或者对象都没有访问权限。
③protected。表明该成员变量或方法对自己及其子类或与其位于同一包内的类是可见的。
④default·。表明该成员变量或方法只有自己和与其位于同一包内的类可见。(若父类与子类在同一包,则可访问;否则没有访问权限)
6. 接口
由于Java不支持多重继承,即一个类只能有一个父类,为了克服单继承的缺点,Java引入了接口这一概念。接口是抽象方法定义的集合,是一种特殊的抽象类。接口中只包含方法的定义,没有方法的实现。接口中的所有方法都是抽象的。接口中成员的作用域修饰符都是public,接口只能给的常量值默认使用public
static final修饰。
在Java中,有些接口内部没有声明任何方法。也就是说,实现这些接口的类不需要重写任何方法,这些没有任何方法声明的接口又被称为标识接口,标识接口对实现它的类没有任何语义上的要求,它仅仅充当一个标识的作用,用来表明实现它的类属于一个特定的类型。
Java类库中已存在的标识接口有Cloneable和Serializable等,在使用时会经常用instanceof来判断实例对象的类型是否实现了一个给定的接口。
public class Man implements Cloneable{ public static void main(String[] args){ Man m = new Man(); System.out.println(m instanceof Cloneable); } }
7. clone()方法——浅复制和深复制
Java在处理基本数据类型时,都是按值传递(传递的是输入参数的复制)的方式执行,除此之外的其他类型都是按引用传递(传递的是对象的一个引用)的方式执行。对象处理在函数调用时是引用传递,在使用“=”赋值时采用引用传递。
Java中所有的类默认都继承自Object类,而Object类中提供了一个clone()方法。这个方法的作用是
1)实现clone的类首先需要继承Cloneable接口,Cloneable接口实际上是一个标识接口,没有任何的接口方法。
2)在类中重写clone()方法。
3)在clone方法中调用super.clone()。无论clone类的继承结构是什么,super.clone()会直接或间接调用java.lang.Object类的clone()方法。
4)把浅复制的引用指向原型对象新的克隆体。
浅复制与深复制的区别:对象的引用是否仍然指向原来的对象。
class Test{ public int i; public StringBuffer s; }
8. 反射机制
反射机制是Java中一个非常重要的特性,它允许程序在运行时进行自我检查,同时也允许其内部的成员进行操作。
反射机制提供的功能主要有:得到一个对象所属的类;获取一个类的所有成员变量和方法;在运行时创建对象;在运行时调用对象的方法。
public class Main implements Cloneable{ public static void main(String[] args){ try{//使用放射机制加载类 Class b = Class.forName("B"); A a = (A) b.newInstance(); a.print(); }catch(Exception e){ e.printStackTrace(); } } } class A{ public void print(){ System.out.println("A"); } } class B extends A{ public void print(){ System.out.println("B"); } }
如何获取class类:
1) class。forName(“类的路径”),如上例所示。
2)类名.class
3)实例.getClass()
Java创建对象的方法:
1)通过new语句实例化一个对象
2)通过反射机制创建对象,见上例
3)通过clone()方法创建一个对象,见7
4)通过反序列化的方式创建对象
9. 实现类似C语言中函数指针的功能
在C语言中,有一个非常重要的概念——函数指针,其最重要的功能是实现回调函数。所谓回调函数,就是指函数先在某处注册,而它将在稍后某个需要的时候被调用。
Java中可以利用接口与类来实现同样的效果。具体而言,应先定义一个接口,然后在接口中声明要调用的方法,接着实现这个接口,最后把这个实现类的一个对象作为参数传递给调用程序,调用程序通过这个参数来调用指定的函数,从而实现回调函数的功能。
interface IntCompare{ public boolean cmp(int x,int y); } class Cmp1 implements IntCompare{ public boolean cmp(int x,int y){ if(x > y){ return true; }else{ return false; } } } class Cmp2 implements IntCompare{ public boolean cmp(int x,int y){ if(x > y){ return false; }else{ return true; } } } public class SelectSort_s { public static void SelectSort(int[] a, IntCompare cmp){ for(int i = 0; i < a.length; i++){ for(int j =i+1; j < a.length; j++){ if(cmp.cmp(a[i], a[j])){ swap(a,i,j); } } } } public static void swap(int[] a, int x, int y){ int temp = a[x]; a[x] = a[y]; a[y] = temp; } public static void main(String[] args) { int[] array = {4,2,1,6,3,6,0,-5,1,1}; SelectSort(array, new Cmp1()); //升序排序 // SelectSort(array, new Cmp2()); //降序排序 for(int i = 0; i < array.length; i++){ System.out.printf("%d ",array[i]); } } }
上例定义了一个用来比较大小的接口IntCompare,这个接口实际上充当了C语言中函数指针的功能,在使用时,开发人员可以根据实际需求传入自定义的类。在上例中分别有两个Cmp1和Cmp2都实现了这个接口,分别用来在实现升序排序和 上例定义了一个用来比较大小的接口IntCompare,这个接口实际上充当了C语言中函数指针的功能,在使用时,开发人员可以根据实际需求传入自定义的类。在上例中分别有两个Cmp1和Cmp2都实现了这个接口,分别用来在实现升序排序和降序排序时使用。降序排序时使用。
参考文献:
《Java程序员面试笔试宝典》