JAVA知识点总结

Java基础概念

(1)Java语言有哪些优点?

a. java为纯面向对象的语言;b. 平台无关性;c. java提供了很多内置的类库;d. 提供了对Web应用开发的支持;e. 具有较好的安全性和健壮性;f. 去除了C++中难以理解、容易混淆的特性,例如头文件,指针,结构,单元,运算重载符,虚拟基础类,多重继承等。

(2)Java与C/C++有什么异同。

     java与C++都是面向对象语言,都使用了面向对象思想(例如封装,继承,多态),由于面向对象有许多非常好的特性(继承、组合),因此二者都有很好的可重用性。主要介绍一下不同点:

a. java为解释性语言,其运行过程为:程序源代码经过java编译器编译成字节码,然后由JVM解释执行。C/C++为编译型语言,源代码经过编译和链接后生成可执行的二进制代码。因此,java的执行速度比C/C++慢,但是java能够跨平台而C/C++不能。

b. java为纯面向对象语言,所有代码(包括函数、变量)必须在类中实现,除基本数据类型(包括int,float等)外,所有类型都是类。此外,java中不存在全局变量或全局函数,而C++兼具面向过程和面向编程的特点,可以定义全局变量和全局函数。

c. java中没有指针的概念

d. java 语言不支持多重继承,但是java语言引入了接口的概念,可以同时实现多个接口。

e. C++语言中,需要开发人员去管理对内存的分配(包括申请和释放),而java语言提供了垃圾回收器来实现垃圾的自动回收,不需要程序显式的管理内存的分配。

(3)  为什么需要public static void main(String[] args)这个方法?

public  static void main(String[] args) 为java程序的入口方法,JVM在运行程序时,会首先查找main()方法。其中,public是权限修饰符,表明任何类或者对象都可以访问这个方法,static表明main()是一个静态方法,即方法中的代码是储存在静态存储区的,只要类被加载后,就可以使用该方法而不需要通过实例化对象来访问,可以直接通过类名.main()直接访问,main是JVM识别的特殊方法名,是程序的入口方法。

(4) 如何实现在main()方法执行前输出“Hello World”

众所周知,在java中,main()方法是程序的入口方法,在执行运行时,最先加载的就是main()方法,但这并不意味着main()方法就是程序运行时第一个被执行的模块。

java中,由于静态块在类被加载的时候就会被调用,因此可以在main()方法执行前,利用静态块实现输出“Hello World”的功能。静态块不管顺序如何,都会在main()方法执行之前执行。

(5) java中的作用域有哪些?

在计算机程序中,生命在不同地方的变量具有不同的作用域,例如局部变量、全局变量等,在java语言中,作用域是由花括号的位置决定的,它决定了其定义的变量名的可见性与生命周期。

变量的类型主要有3种:成员变量(public,private,protected,default)、静态变量和局部变量。

(6) 一个java文件中是否可以定义多个类?

一个java文件中可以定义多个类,但是最多只能有一个类被public修饰,并且这个类的类名与文件名必须相同,若这个文件没有public类,则文件名随便是一个类的名字即可。需要注意的是:当用javac指令编译这个.java文件时,它会给每个类生成一个对应的.class文件。

(7) 什么是构造函数?

构造函数是一种特殊的函数,用来在对象实例化时初始化对象的成员变量。构造函数的特点有:

a. 构造函数必须与类名相同,并且不能有返回值(返回值也不能为void)

b. 每个类可以由多个构造函数。

c. 构造函数可以有0个,1个或1个以上的参数。

d. 构造函数总是伴随着new操作一起调用,且不能由程序的编写者直接调用,必须由系统调用。构造函数在对象实例化时会被自动调用,且只运行一次;而普通方法是在程序执行到它时被调用,且可以被该对象调用多次。

e. 构造函数的主要作用是完成对象的初始化工作。

f. 构造函数不能被继承,因此不能被覆盖,但是构造函数能够被重载,可以使用不同的参数个数或参数类型来定义多个构造器。

(8) 为什么java中有些接口没有任何方法?

由于java不支持多继承,即一个类只能有一个父类,为了克服单继承的缺点,java语言引入了接口这一概念。接口是抽象方法定义的集合(接口中也可以定义一些常量值),是一种特殊的抽象类。接口中只包含方法的定义,没有方法的实现。java8开始,接口开始可以默认方法与静态方法。接口中的所有方法都是抽象的。接口中成员的作用域修饰符都是public,接口中的常量默认使用public static final修饰。由于一个类可以实现多个接口,因此通常可以采用实现多个接口的方式来间接达到多重继承的目的。

   在java中,有些接口内部没有实现任何方法,也就是说,实现这些接口的类不需要重写任何方法,这些没有任何方法声明的接口又被叫做标识接口,标识接口对实现它的类没有任何语义上的要求,它仅仅充当一个标识作用,用来表明实现它的类属于一个特定的类型。eg:java类库中已存在的标识接口有Coloneable和Serializable等。在使用时会经常用instanceof来判断实例对象的类型是否实现了一个特定的标识接口。

(9) 什么是反射机制?

反射机制是Java语言中一个非常重要的特征,它允许程序在运行时进行自我检测,同时也允许对其内部的成员进行操作。虽然这个特性在实际开发时使用不多,但很多语言就没有提供这种特性。由于反射机制能够实现在运行时对类进行装载,因此能够增强程序的灵活性,但是不恰当的反射机制,也会严重影响系统的性能。

反射机制提供的功能主要包括:a. 得到一个对象所属的类;b. 获取一个类的所有成员变量和方法;c. 在运行时创建对象;d. 在运行时调用对象的方法。

在反射机制中,Class是一个非常重要的类,那么如何获取Class类呢?有三种:a. Class.forName("类的路径");b. 类名. Class; c. 实例.getClass().

(10) Java创建对象的方法:

a. 通过new语句实例化一个对象; b. 通过反射机制创建对象;c. 通过clone()方法创建一个对象;d. 通过反序列化的方式创建对象。

(11) package有什么作用?

package的中文意思是“包”,它是一个比较抽象的逻辑概念,其宗旨是把.java文件(Java源文件)、.class文件(编译后的文件)以及其他resource文件(例如.xml文件、.avi文件、.mp3文件、.txt文件)有条理的进行一个组织,以供使用。它类似于Linux文件系统由一个根,从根开始有目录和文件,然后目录中嵌套目录。

package作用:a. 提供多层命名空间,解决命名冲突,通过使用package,使得处于不同package中的类可以存在相同的名字。

b. 对类按功能进行分类,使项目的组织更加清晰。当开发一个有非常多的类的项目时,如果不使用package对类进行分类,而是把所有类都放在一个package下,这样的代码不仅可读性差,而且可维护性也差,会影响开发效率。

面向对象技术

(1)面向对象与面向过程有什么区别?

面向对象是当今软件开发方法的主流方法之一,它是把数据及对数据的操作方法放在一起,作为一个相互依存的整体,即对象。对同类对象抽象出其共性,即类,类中的大多数数据,只能被本类的方法进行处理。类通过一个简单的外部接口与外界发生关系,对象与对象之间通过消息进行通信。

面向过程是一种以事件为中心的开发方法,就是自顶向下顺序执行,逐步求精,其程序结构是按功能划分为若干个基本模块,这些模块形成一个树状结构,各模块之间的关系也比较简单,在功能上相对独立,每一模块内部一般都是由顺序、选择和循环3种基本结构组成,模块化实现的具体方法是使用子程序,而程序流程在写程序时就已决定。

面向对象与面向过程的不同之处:

a. 出发点不同:面向对象方法是用符合常规思维的方式来处理客观世界的问题,强调把问题域的要领直接映射到对象及对象之间的接口上。面向过程方法强调的是过程的抽象化与模块化,它是以过程为中心构造或处理客观世界问题的。

b. 层次逻辑关系不同:面向对象方法是用计算机逻辑来模拟客观世界中的物理存在,以对象的集合类作为处理问题的基本单位,尽可能的使用计算机世界向客观世界靠拢,以使问题的处理更清晰直接,面向对象方法是用类的层次结构来体现类之间的继承金和发展。面向过程处理问题的基本单位是能清晰准确的表达过程的模块,用模块的层次结构概括模块或模块间的关系与功能,把客观世界的问题抽象成计算机可以处理的过程。

c. 数据处理方式与控制程序方式不同:面向对象方法将数据与对象的代码封装成一个整体,原则上其他对象不能直接修改其数据,即对象的修改只能由自身的成员函数完成,控制程序方式上是通过“事件驱动”来激活和运行程序。面向过程是直接通过程序来处理数据,处理完毕后可显示处理结果,在控制程序方式上是按照设计调用或返回程序,不能自由导航,各个模块之间存在着控制与被控制、调用与被调用之间的关系。

d. 分析设计与转换方式不同:面向对象方法贯穿于软件生命周期的分析、设计以及编码中,是一种平滑过程,从分析到设计再到编码是采用一致性的模型表示,即实现的是一种无缝连接。面向过程方法强调分析、设计及编码之间按规则进行转换,贯穿于软件生命周期的分析、设计及编码中,实现的是一种有缝的链接。

(2)面向对象的开发方式有什么优点?

采用面向对象的开发方式有诸多优点,主要有3个:

a. 较高的开发效率;采用面向对象的开发方式,可以对现实的事物进行抽象,可以把现实的事物直接映射为开发的对象,与人类的思维过程相似。其次,面向对象的开发方式可以通过继承或者组合的方式来实现代码的重用,因此可以大大地提高软件的开发效率。

b. 保证软件的鲁棒性:正是由于面向对象的开发方法有很高的重用性,在开发的过程中可以重用已有的而且在相关领域经过长期测试的代码,因此,自然而然地对软件的鲁棒性起到了良好的促进作用。

c. 保证软件的高可维护性。由于采用面向对象的开发方式,使得代码的可读性非常好,同时面向对象的设计模式也使得代码结构更加清晰了。同时针对面向对象的开发方式,已有许多非常成熟的设计模式,这些设计模式可以使得程序在面对需求的变更时,只需要修改部分的模块就可以满足需求,因此维护起来方便。

(3)什么是继承?

继承是面向对象中的一个非常重要的特性。通过继承,子类可以使用父类中的一些成员变量与方法,从而能够提高代码的复用性,提高开发效率。在java中,被继承的类叫做基类(superclass)或父类,继承父类的类叫派生类或子类(subclass)。继承是通过extends关键字来实现的。

继承主要有4个特性:

a. java语言不支持多重继承,也就是说,子类至多能有一个父类,但是可以通过实现多个接口来达到多重继承的目的。

b. 子类只能继承父类的非私有(public与protected)成员变量与方法。

c.当子类中的方法与父类中的方法有相同的函数签名(相同的方法名,相同的参数个数与类型)时,子类将会覆盖父类的方法,而不会继承。

d. 当子类中定义的成员变量和父类中定义的成员变量同名时,子类中的成员变量会覆盖父类的成员变量,而不会继承。

(4)组合和继承有什么区别?

组合和继承是面向对象中两种代码复用的方式,组合是指在新类里面创建原有类的对象,重复利用已有类的功能。继承是面向对象的主要特征之一,它允许设计人员根据其他类的实现来定义一个类的实现。组合和继承都允许在新的类中设置子对象,只是组合是显示的,而继承是隐式的,组合和继承存在着对应关系:组合中的整体类和继承中的子类对应,组合中的局部类和继承中的父类对应。

继承和组合都可以实现代码的重用,则在选择的时候要遵循以下两点原则:

a. 除非两个类之间是is-a的关系,否则不要轻易的使用继承,不要单纯的为了实现代码的重用而使用继承,因为过多的使用继承会破坏代码的可维护性,当父类被修改时,会影响到所有继承自它的子类,从而增加程序的维护难度与成本。

b. 不仅仅为了实现多态而使用继承,如果类没有is-a的关系,可以通过实现接口与组合的方式来达到相同的目的。设计模式中的策略模式很好的说明这一点,采用接口与组合的方式比采用继承的方式具有更好的可扩展性。

由于java语言只支持单继承,如果想同时继承两个类或多个类,在java中是无法实现的。同时,在java中,如果继承使用太多,也会让一个class里面的内容变得臃肿。所以在java中,能使用组合就尽量不要使用继承。

(5)多态的实现机制是什么?

多态是面向对象程序设计中代码重用的一个重要机制,它表示当同一个操作作用在不同对象时,会有不同的语义,从而产生不同的结果,eg:同样是执行“+”操作,“3+4”用来表示整数相加,而“3”+“4”却实现了字符串的相连。在java中,多态主要有两种表现方式:

a. 方法的重载(overload),重载是指同一个类中有多个同名的方法,但这些方法有着不同的参数,因此在编译时就能确定调用哪个方法,它是一种编译时多态,重载可以看做一个类中的方法多态性。

b. 方法的覆盖(override),子类可以继承父类的方法,因此同样的方法会用在父类与子类中有着不同的表现形式,在java中,基类的引用变量不仅可以指向基类的实例对象,也可以指向其子类的实例对象。同样,接口的引用变量也可以指向其实现类的实现对象。而程序调用的方法在运行期才动态绑定(绑定指的是将一个方法调用和另一个方法主题连接到一起),就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。通过这种动态绑定的方法实现了多态。由于只有在运行时才确定调用哪个方法。因此通过方法覆盖实现的多态也可以称为运行时多态。

(6)重载和覆盖有什么区别?

重载(overload)和覆盖(override)是java多态性的不同表现方法。

其中,重载是在一个类中多态性的一种表现,是指在一个类中定义了多个同名方法,他们或者有不同的参数个数,或者有不同的参数类型。在使用重载时,需要注意3点:

a. 重载是通过不同的方法参数来区分的,例如不同的参数个数、不同的参数类型或不同的参数顺序。

b. 不能通过方法的访问权限、返回值类型和抛出的异常类型来进行重载。

c. 对于继承来说,如果基类方法的访问权限是private,那么就不能在派生类对其重载;如果派生类也定义了一个同名的函数,这只是一个新方法,不会达到重载的效果。

覆盖是指派生类函数覆盖基类函数。覆盖一个方法并对其重写,以达到不同的作用。在使用时需注意4点:

a. 派生类中的覆盖方法必须要和基类中被覆盖的方法有相同的函数名和参数。

b. 派生类中的覆盖方法的返回值必须和基类中覆盖的方法的返回值相同。

c. 派生类中覆盖方法所抛出的异常必须和基类中被覆盖的方法所抛出的异常一致。

d. 基类中被覆盖的方法不能为private,否则其子类只是定义了一个方法,并没有对其覆盖。

重载和覆盖的区别有以下4个方面:

a. 覆盖是子类和父类的关系,是垂直的关系;重载是同一个类中方法之间的关系,是水平关系;

b. 覆盖只能由一个方法或只能由一对方法产生关系;重载是多个方法之间的关系。

c. 覆盖要求参数列表相同,重载要求参数列表不同;

d. 覆盖关系中,调用方法体是根据对象的类型(对象对应存储空间类型)来决定;而重载关系是根据调用时的实参表与形参表来选择方法体的。

(7)抽象类(abstract class)与接口(interface)有什么异同?

如果一个类中包含抽象方法,那么这个类就是抽象类。在java中,可以通过把类或者类中的某些方法声明为abstract(abstract只能用来修饰类或方法,不能用来修饰属性)来表示一个类是抽象类。接口就是指一个方法的集合,接口中的方法都没有方法体,在Java中,接口是通过interface来实现的。

抽象类(abstract class) 和接口(interface)都是支持抽象类定义的两种机制(注意:此句中两个抽象类的 意义不一样,前者表示的是一个实体,后者表示的是一个概念)。二者有很大的相似性,甚至有时候是可以互换的,但同时,二者也存在很大的区别:

a. 只要包含一个抽象方法的就必须被声明为抽象类,抽象类可以声明方法的存在而不去实现 它,被声明为抽象的方法不能包含方法体。在实现时,必须包含相同的或者更低的访问级别(public--->protected---->private)。抽象类在使用的过程中不能被实例化但是可以创建一个对象使其指向具体子类的一个实例。抽象类的子类为父类中的所有抽象方法提供具体的实现,否则他们也是抽象类。接口可以被看做抽象类的变体。接口中的所有方法都是抽象的,可以通过接口来间接的实现多继承。接口中的成员变量都是static final类型。由于抽象类可以包含部分方法的实现,因此,在一些场合下抽象类比接口存在更多的优势。

接口与抽象类的相同点有以下2点:

a. 都不能被实例化;

b. 接口的实现类或者抽象类的子类都只有实现了接口或者抽象类中的方法后才能被实例化。

接口与抽象类的不相同点有以下5点:

a. Java8之前,接口只有定义,其方法不能在接口中实现,只有实现接口的类才能实现接口中定义的方法,而抽象类可以有定义与实现,即其方法可以在抽象类中被实现。

b. 接口需要实现(implements)但抽象类只能被继承(extends)。一个类可以实现多个接口,但是一个类只能继承一个抽象类,因此使用接口可以间接的达到多重继承的目的。

c. 接口强调特定功能的实现,其设计理念是“has-a”关系;而抽象类强调所属关系,其设计理念为“is-a”关系。

d. 接口中定义的成员变量默认为public static final,只能够有静态的不能被修改的数据成员,而且,必须给其赋初值,其所有成员方法都是public,abstract的,而且只能被这两个关键字修饰。抽象类可以有自己的数据成员变量,也可以有非抽象的成员方法,而且,抽象类中的成员变量默认为default(本包可见),当然也可以定义为privta,protected和public,这些成员变量可以在子类中被重新定义,也可以被重新复制,抽象类中的抽象方法(其前有abstract修饰)不能用private,static,synchronized,native等访问修饰符修饰,同时方法必须以分号结尾,并且不带花括号。所以,当功能需要累计时,用抽象类,不需要累计时,用接口。

e. 接口被用于实现比较常用的功能,便于日后维护或者添加删除方法;而抽象类更倾向于充当公共类的角色,不适用于日后对代码进行修改。

简单点说,接口是一种特殊形式的抽象类,使用接口完全有可能实现与向抽象类相同的操作,但一般而言,抽象类多用于在同类事物中有无法描述的场景,所以当子类和父类之间存在有逻辑上的层次结构时,推荐使用抽象类;而接口多用于不同类之间,定义不同类之间的通信规则,所以当希望支持差别较大的两个或更多对象之间的特定交互行为时,应该使用接口。

此外,接口可以继承接口,抽象类可以实现接口,抽象类也可以继承具体类。抽象类也可以有静态的main方法。

(8)内部类有哪些?

在java中,可以把一个类定义到另一个类的内部,在类里面的这个类就叫做内部类,在外面的类叫做外部类。在这种情况下,这个内部类可以被看做外部类的一个成员(与类的属性和方法类似)。还有一种类被称为顶层(top-level)类,指的是类定义代码不镶嵌在其他类定义中的类。

内部类可以分为很多种,主要分为4种:静态内部类(static inner calss),成员内部类(member inner calss),局部内部类(local inner calss)和匿名内部类(anonymous inner class),定义如下:

class outerClass{
    static class innerClass{}   //静态内部类}
class outerClass{
    class innerClass{}          //成员内部类(普通内部类)}
class outerClass{
    public void memberFunction(){
        class innerClass{}     //局部内部类
        }
}


public class MyFrame extends Frame{     //外部类
public MyFrame(){
        addWindowListener(new WindowAdapter() {   //匿名内部类
            public void windowClosing(WindowEvent e){
            dispose();
            System.exit(0);
            }
      });
    }
}

       静态内部类是指被声明为static的内部类,它可以不依赖于外部类实例而被实例化,而通常的内部类需要在外部类实例化后才能实例化。静态内部类不能与外部类有相同的名字,不能访问外部类的普通成员变量,只能访问外部类中的静态成员和静态方法(包括私有类型)。

一个静态内部类,如果去掉static关键字,就成为成员内部类。成员内部类为非静态内部类,它可以自由的引用外部类的属性和方法,无论这些属性和方法是静态还是非静态的。但是他与一个实例绑在了一起,不可以定义静态的属性和方法。只有在外部的类被实例化后,这个内部类才能被实例化。需要注意的是,非静态内部类中不能有静态成员。

局部内部类指的是定义在一个代码块内的类,它的作用范围是其所在的代码块,是内部类中最少使用到的一种类型。局部内部类像局部变量一样,不能被public,protected,private以及static修饰,只能访问方法中定义为final类型的局部变量。对于一个静态内部类,去掉其声明中的“static”关键字,将其定义移入其外部类的静态方法或者静态初始化代码中就成为了局部内部类。局部静态内部类与静态内部类的基本特性相同。局部内部类与内部类的基本特性相同。

匿名内部类是一种没有类名的内部类,不适用关键字class,extends,implements,没有构造函数,它必须继承其他类或实现其他接口。匿名内部类的好处是代码更加简洁、紧凑,但带来的问题是易读性下降。它一般应用于GUI(Graphical User Interface,图形用户界面) 编程中实现时间处理等。在使用匿名内部类时,要记住以下几个原则:

a. 匿名内部类不能有构造函数。

b. 匿名内部类不能定义静态成员,方法和类

c. 匿名内部类不能是public, protected, private, static

d. 只能创建匿名内部类的一个实例

e. 一个匿名内部类一定是在new之后,这个匿名内部类必须继承一个父类或实现一个接口。

f. 因为匿名内部了为局部内部类,所以具备内部类的所有限制都对其生效。

(9)如何获取父类的类名?

Java语言提供了获取类名的方法:getClass().getName(),开发人员可以调用这个方法来获取类名,代码如下:

public class Solution {
	public void test(){
		System.out.println(this.getClass().getName());
	}
	public static void main(String[] args) {
		new Solution().test();
	}
}

但是如果Solution继承了类A则上面的代码还是返回Solution。因为Java中任何语言都继承自Object类,getClass()方法在Object类中被定义为final与native,子类不能覆盖该方法,因此this.getClass()和super.getClass()最终都调用的是Object中的getClass()方法。而Object的getClass()方法的释义是:返回此Object的运行时的类。由于运行的是Solution类而不是A类,因此输出的是Solution。

用getClass().getSuperclass().getName()可以获取类名。

(10)this和super有什么区别?

在java中,this用来指向当前实例对象,它的一个非常重要的作用就是用来区分对象的成员变量与方法的形参(当一个方法的形参与成员变量的名字相同时,就会覆盖成员变量)。

public People{
    String name;
    public People(String name){  //正确的方法
        this.name = name;
    }
    public People(String name){
        name = name;             //错误的写法
    }
}

第一个构造函数使用this.name来表示左边的值为成员变量,而不是这个构造函数的形参。对于第二个构造函数,由于在这个函数中形参与成员变量有着相同的名字,因此对于语句 name = name,等号左边右边的两个name都代表的是形参。在这种情况下,只有this才能访问到成员变量。

super可以用来访问父类的方法或者成员变量。当子类的方法或者成员变量与父类有相同名字时也会覆盖父类的方法或者成员变量要想访问父类的方法或者成员变量只能通过super关键字来访问。super()必须为构造函数中的第一条语句。

关键字

(1)变量命名有哪些规则?

在java中,变量名、函数名、数组名统称为标识符,java语言规定标识符只能由字母(a~z,A~Z)、数字(0~9)、下划线(_)和$组成,并且标识符的第一个字符必须是字母、下划线或者$。此外,标识符也不能包含空白字符(换行符、空格和制表符)。

以下标识符都是非法的:

char:char是java语言的一个数据类型,是保留字,不能作为标识符,其他如int,float等与之类似。

number of book:标识符中不能有空格。

3com:标识符不能以数字开头。

a*b: 不能以*作为标识符的字符。

值得注意的是:在java中,变量名是区分大小写的,例如Count与count被认为是两个不同的标识符,而非相同的标识符。

(2)break、continue以及return有什么区别?

break用于直接强行跳出当前循环,不再执行剩余代码。当循环中遇到break语句时,忽略循环体中任何其他语句和循环条件测试,程序控制在循环体后面的语句重新开始。所以,当多层循环嵌套,并且break语句出现在循环嵌套中的内层循环时,它将仅仅只是终止了内层循环的执行,而不影响外层循环的执行。

continue用于停止当前循环,回到循环起始处,进入下一次循环操作。continue语句之后的语句将不再执行,用于跳过循环体中的一部分操作,也就是不执行这部分语句,而不是跳出整个循环执行下一条语句。continue中断一次循环的执行而已。

return语句时一个跳转语句,用来表示从一个方法返回(返回一个值或其他复杂类型),可以使程序控制返回到调用该方法的地方。当执行main方法时,return语句可以使程序执行返回到java运行系统。

引申:java语言中是否存在关键字goto?

虽然关键字goto作为java的保留字,但目前并没有在java中使用。在C/C++中,goto常用于跳出多重循环,而在java中,可以使用break和continue来达到相同的效果。那么既然goto没有在java中使用,为什么还要把它作为保留字呢?其中一个原因就是这个关键字有可能会在将来被使用。如果不把goto作为保留字,开发人员就有可能用goto作为变量名来使用。一旦有一天java支持了goto关键字了,这就会导致以前的程序无法正常运行。因此把goto作为保留字是非常必要的。

(3)final、finally以及finalize有什么区别?

final用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。finally是异常处理语句结构的一部分,表示总是执行。finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。

引申:JDK中哪些类是不能被继承的?

不能被继承的类是那些用final关键字修饰的类。一般比较基本的类型为防止扩展类无意间破坏原来方法的实现的类型都应该是final的,在JDK中,String,StringBuffer等都是基本类型,所以,String,StringBuffer等类是不能继承的。

(4)assert有什么作用?

断言(assert)作为一种软件调试的方法,提供了一种在代码中进行正确性检查的机制,目前很多开发语言都支持这种机制。它的主要作用是对一个boolean表达式进行检查,一个正确运行的程序必须保证这个boolean表达式的值为true,若boolean表达式的值为false,则说明程序已经处于一种不正确的状态下,系统需要提供警告并且推出程序。

(5)static关键字有哪些作用?

static 关键字主要有两种作用:第一:为某特定类型或对象分配单一的存储空间,而与创建对象的个数无关。第二:实现某个方法或属性与类而不是对象关联在一起,也就是说,在不创建对象的情况下就可以通过类来直接调用方法或使用类的属性。

(6)volatile有什么作用?

在java编程语言中,有时为了提高代码的运行效率,编译器会自动对代码进行优化,把经常访问的变量缓存起来,程序在读取这个变量时可能会直接从缓存(例如寄存器)中来读取这个值,而不会去内存中读取。这样做的好处是提高了代码的运行效率,但当遇到多线程编程时,变量的值可能会因为别的线程而改变了,而该缓存的的值不会变,从而造成应用程序读取的值和实际的变量值不一致,例如,在本次线程内,当读取一个变量时,为提高存取速度,会先把变量读取到一个缓存中,当以后再取变量值时,就直接从缓存中取值,当变量在本线程里改变时,会同时把变量的新值复制到该缓存中,以便保持一致。

volatile是一个类型修饰符,它是被设计用来修饰不同线程访问和修改的变量。被volatile类型定义的变量,系统每次用到它时都是直接从对应的内存中提取,而不会利用缓存。在使用了volatile修饰成员变量后,所有线程在任何时候所看到变量的值都是相同的。

(7)instanceof有什么作用?

instanceof是java语言中的一个二元运算符,它的作用是判断一个引用类型的变量所指向的对象是否是一个类(或接口、抽象类、父类)的实例,即它左边的对象是否是它右边的类的实例,该运算符返回boolean类型的数据。

(8)strictfp有什么作用?

关键字strictfp是strict float point的缩写。指的是精确浮点,它用来确保浮点数运算的准确性。JVM在执行浮点数运算时,如果没有指定strictfp关键字,此时计算结果可能会不精确,而且计算结果在不同平台或厂商的虚拟机上会有不同的结果,导致想不到的错误。而一旦使用了strictfp来声明一个类、接口或方法,那么在所声明的范围内,java编译器以及运行环境会完全依照IEEE二进制浮点算数标准来执行,在这个关键字声明的范围内,所有浮点数的计算都是精确的。需要注意的是,当一个类被strictfp修饰时,所有方法都会自动被strictfp修饰。因此,strictfp可以保证浮点数运算的精确性,而且在不同的硬件平台上会有一致的运行结果。

基本类型与运算

(1)什么是不可变类?

不可变类(immutable class)是指当创建了这个类实例后,就不允许修改它的值了,也就是说,一个对象一旦被创建出来,在其整个生命周期中,它的成员变量就不能修改了。它优点类似于常量(const),只允许别的程序读,不允许别的程序进行修改。在java类库中,所有基本包装类都是不可变类,如:Integer,Float等,此外String也是不可变类。

创建一个不可变类要遵循:

a. 类中没有成员变量被private修饰;

b. 类中没有写或者修改成员变量的方法,例如setXXX, 只提供构造函数,一次生成,永不改变。

c. 确保类中所有方法不会被子类覆盖,可以通过把类定义为final或者把类中的方法定义为final来达到这个目的。

d. 如果一个类成员不是不可变,那么在成员初始化或者使用get方法获取该成员变量时,需要通过clone方法来确保类的不可变性。

(2)值传递与引用传递有哪些区别?

方法调用是编程语言中非常重要的一个特性,在方法调用时,通常需要传递一些参数来完成特定的功能。java语言提供了两种参数传递的方法:值传递和引用传递。

a. 值传递:在方法调用中,实参会把它的值传递给形参,形参只是用实参的值初始化一个临时的存储单元,因此形参与实参虽然有着相同的值,但是却有着不同的存储单元,因此对形参的改变不会影响实参的值。

b. 引用传递:在方法调用时,传递的是对象(也可以看作是对象的地址),这时形参与实参的对象指向同一块存储单元,因此对形参的改变就会影响实参的值。

 在java中,8种基本数据类型是按值传递,其他所有类型都是按引用传递。

(3)不同数据类型的转换有哪些规则?

在java中,当参与运算的两个变量的数据类型不同时,就要进行隐式的数据类型转换,转换的规则为:从低精度向高精度转换,即优先级满足 byte<short<char<int<long<float<double,例如在不同数据类型的值在进行运算时,short能够自动转为int类型,int能够自动转换为float类型等。反之,则需要通过强制类型转换实现。

(4)Math类中round、ceil、和 floor 方法的功能是什么?

字符串与数组

异常处理

输入输出流

Java平台与内存管理 

容器

(1)ArrayList,Vector 和 LinkedList 有什么区别?

ArrayList,Vector 和 LinkedList 均在java.util包中,均为可伸缩数组,即可以动态变长度的数组。

ArrayList 和 Vector 都是基于存储元素的Object[] array来实现的,他们会在内存中开辟一块连续的空间来存储。由于数组存储是连续的,因此他们支持用序号(下标)来访问元素,同时索引数据的速度比较快。但是在插入元素时需要移动容器中的元素,所以对数据的插入操作执行的比较慢。ArrayList 和 Vector 都有一个初始化的容器的大小,当里面存储的元素超过这个大小就需要动态地扩充他们的存储空间。为了提高程序的效率,每次扩充容量,不是简单地扩充一个存储单元,而是一次增加多个存储单元。Vector 默认扩充为原来的2倍(每次扩充空间的大小是可以设置的),而ArrayList默认扩充为原来的1.5倍(没有提供方法来设置空间扩充的方法)。

ArrayList 与 Vector最大的区别就是 synchronization(同步)的使用,没有一个ArrayList的方法是同步的,而Vector的绝大多数方法(例如add,insert,remove,set,equals,hashcode等)都是直接或间接同步的,所以Vector是线程安全的,ArrayList不是线程安全的。正是由于Vector提供了线程安全的机制,其性能上也要略逊与ArrayList。

LinkedList是采用双向列表来实现的,对数据的索引需要从列表头开始遍历,因此用于随机访问则效率比较低,但是插入元素时不需要对数据进行移动,因此插入效率较高。同时,LinkedList是非线程安全的容器。

总结!!当对数据的主要操作是索引或只在集合的末端增加、删除元素时,使用ArrayList 或 Vector 效率比较高;当对数据的操作主要为指定位置的插入或删除操作时,使用LinkedList效率比较高;当在多线程中使用容器时(即多个线程会同时访问该容器),选用Vector较为安全。

 

多线程

(1)如何实现多线程?哪种方法更好?

a.继承Thread类,重写run()方法;b.实现Runnable接口,并实现该接口中的run()方法;c.实现Callable接口,重写call()方法;

因为Java不支持类的多重继承,但允许调用多个接口。所以如果要继承其他类,当然是调用Runnable接口好了。

(2)Thread 类中的start() 和 run() 方法有什么区别? 

只有通过调用线程类的start()方法才能真正达到多线程的目,start()方法够异步的调用run()方法,但是直接调用run()方法却是同步的。直接调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启 动,start()方法才会启动新线程。

(3)多线程同步的方法? 

a.synchronized关键字:包括synchronized方法与synchronized块。

b.wait()方法与notify()方法

c.Lock():包括lock()以阻塞的方式获取锁;tryLock()以非阻塞的方式获取锁;tryLock(long timeout,TimeUnit unit)设置等待时间;lockInterruptibly()如果获得了锁立即返回若没有获取锁则当前线程处于休眠状态。

(4)sleep()方法与wait()方法有什么区别?

a. sleep是线程类(Thread)的方法,导致此线程暂停执行指定事件,把执行机会给其他线程,但是监控状态依然保持,到时会自动恢复,调用sleep不会释放对象锁。

b. wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。

(5)终止线程的方法有哪些?

在java语言中可以使用stop()和suspend()方法来终止线程的执行,但是由于潜在的死锁威胁因此java语言已经不建议使用以上两种方法来终止线程了。

一般建议采用的方法是让线程自行结束进入Dead状态。一个线程进入Dead状态,即执行完run()方法,也就是说,如果想要停止一个线程的执行,就要提供某种方式让线程能够自动结束run()方法的执行。在实现时,可以通过设置一个flag标志来控制循环是否执行,通过这种方法来让线程离开run()方法从而终止线程。

(6)同步(synchronized)与锁(Lock)的区别?

a. 用法不同:synchronized既可以加在方法上,也可以加在特定代码块上,而lock需要显示指定起始位置和终止位置。synchronized是托管给JVM执行的,lock的锁是通过代码实现的,它有比synchronized更精确的线程语义。

b. 性能上的不同:lock的接口实现类ReentrantLock,不仅具有和synchronized相同的并发性和语义内存,还多了超时的获取锁,定时锁,等候和中断锁。在竞争不是很激烈的情况下,synchronized的性能优于ReentrantLock,竞争激烈的情况下,synchronized的性能下降的非常快,而ReentrantLock则基本不变。

c. 锁机制不同:synchronized获取锁和释放锁都是在块结构中,当获取多个锁时,必须以相反的方式释放,并且是自动解锁。而Lock则需要人员手动释放,并且必须在finally中释放,否则会引起死锁。

(7)什么是守护线程?

Java提供了两种线程:守护线程和用户线程。守护线程又称为“服务进程”“精灵线程”或“后台线程”,是指在程序运行时在后台提供一种通信服务的线程,这种线程并不属于程序中不可或缺的部分,讲通俗一点就是整个JVM中所有非守护线程的“保姆”

框架

(1)什么是IoC?

IoC(Inversion of Control,控制倒转)是spring的核心。所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。

(2)什么是AOP?

面向切面编程(Aspect-Oriented Programming,AOP)是对面向对象来发的一种补充,它允许开发人员在不改变原来模型的基础上动态的修改模型以满足新的需求,例如,开发人员可以在不改变原来业务逻辑模型的基础上可以动态的增加日志、安全或者异常处理的功能。

下面介绍一个在Apring中使用AOP编程的简单的例子。

1>创建一个接口以及实现这个接口的类。TestAOPIn.java的内容如下:

public interface TestAOPIn{

           public void doSomething();

}

TestAOPImpl.java文件的内容如下:

public class TestAOPImpl implements TestAOPIn{

         public void doSomething(){

                System.ont.println("TestAOPImpl: doSomething");

         }

}

2>配置SpringConfig.xml,使得这个类的实例化对象可以被注入到使用这个对象的Test类中。(配置beans)

3>在完成配置文件后,编写测试代码;

ApplicationContext ctx = new FileSystemXmlApplicationContext("SpringConfig.xml");

TestAOPIn t = (TestAOPIn) ctx. getBean("testAOPBean");

t.doSomething();

编写完这个模块之后,开发人员需要增加对doSomething()方法调用的跟踪,也就是说,要跟踪该方法何时被调用以及调用何时结束等内容。当然使用传统方法也可以实现该功能,但却会产生额外的开销,即需要自己修改已存在的模块。因此可以采用AOP的方式来实现这个功能。

public class TestAOPImpl implement TestAOPIn{

           public void doSomething(){

                   System.ont.println("beginCall doSomething");

                  System.ont.println("TestAOPImpl: doSomething");

                 System.ont.println("endCall doSomething");

           }

}

为此需要提供用来跟踪函数调用的类。

(2)什么是Spring 框架?

Spring框架主要由7个模块组成,分别是:Spring AOP, Spring ORM, Spring DAO, Spring Web, Spring Context, Spring Web MVC, Spring Core。

Spring有着非常广泛的用途,不仅可以在Web容器中用来管理Web服务器端的模块,例如Servlet,还可以用来管理用于访问数据库的Hibernet。 由于Spring 在管理Business Object(业务对象) 和DAO时使用了IoC和AOP的思想,因此这些被Spring管理的对象都可以脱离EJB容器单独运行和测试。在需要被Spring容器管理时,只需要增加配置文件,Spring框架就会会根据配置文件与相应的机制实现这些对象的管理。

除此之外,使用Spring还有如下好处:

1.在使用J2EE开发多层应用程序时,Spring有效的管理了中间层的代码,由于Spring采用了控制反转和面向切面的编程思想,因此这些代码非常容易单独测试。

2. 使用Spring有助于开发人员培养一个良好的编程习惯:面向接口编程而不是面向类编程。面向接口编程使得程序有更好的可扩展性。

3. Spring对数据的存取提供了一个一致的框架,

4. Spring通过支持不同的事务处理API的方法对事物的管理提供了一致的抽象方法。

5. 使用Spring框架编写的大部分业务对象不需要依赖Spring.

(3)什么是事务?

事务是数据库中一个单独的执行单元(Unit),它通常由高级数据库操作语言(例如SQL)或者编程语言(例如C++,Java等)编写的用户程序的执行所引起。当在数据库中更改数据成功时,在事务中更改的数据便会提交,不再更改。否则,事务就取消或者回滚,更改无效。

事务就是用来保证在错误发生(如断电或卡余额不足)的情况下,交易的平稳性和可预测性的技术。事务必须满足4个属性:原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability),即ACID 4种属性。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值