Q:面向对象编程的四大特性及其含义?
首先四大特性是:封装,继承,多态,抽象
什么是封装?
就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。
封装是把过程和数据包围起来,对数据的访问只能通过已定义的接口。
通俗点即隐藏信息 提供使用接口给别人使用,不让别人直接操作属性或方法。
什么是继承?
继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
其中父类又叫超类或基类,子类又叫派生类。父类是子类的一般化,子类是父类的特化(具体化)。
转型:
向上转型:子类引用的对象转换为父类类型称为向上转型。
通俗地说就是是将子类对象转为父类对象。
此处父类对象可以是接口
向下转型:父类引用的对象转换为子类类型称为向下转型。
情况一:如果父类引用的对象如果引用的是指向的子类对象,那么在向下转型的过程中是安全的。也就是编译是不会出错误的。
什么叫多态?
多态的概念即“一个接口,多个方法”
多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。
其中,方法的重写Overriding和重载Overloading是Java多态性的不同表现
方法重载:是统一各类中写有多个同名方法。
但其中的参数个数、顺序、类型不同
返回值类型、修饰符均没关系
方法重写:是子类继承父类,子类重写父类同名方法。
方法名和参数必须一致
返回值类型也必须和父类方法的返回值类型一致
范围修饰符子类的要比父类的大或等于
什么是抽象?
抽象就是把一个对象分析出各个属性,来替代表达的手法 。
抽就是抽离;象 表象,即表示出来的部分
abstract 关键字
abstract(抽象)可以修饰类、方法
抽象方法:在类中没有方法体的方法,就是抽象方法。
抽象方法的定义:
abstract 返回值类型 方法名();
抽象类:含有抽象方法的类就叫抽象类。
抽象类的定义:
abstract class 类名{}
1 用abstract关键字来修饰一个类时,这个类叫做抽象类;
用abstract来修饰一个方法时,该方法叫做抽象方法。
2 含有抽象方法的类必须被声明为抽象类,
抽象类必须被继承,抽象方法必须被重写。
3 抽象类不能被实例化。
4 抽象方法只需声明,而不需实现某些功能。
接口的特点:
A,接口中一般定义的是常量和抽象方法。
抽象类中可以包含抽象方法,也可以有非抽象方法,
但是有抽象方法的类一定是抽象类。抽象方法不能有方法体。
B,接口(interface)中,方法只能定义抽象方法而且默认是Public,
常量则是public static final 修饰的
(不管有没有这些修饰符,方法和常量默认具这种属性)。
C,一个类可以实现多个无关的接口(这点和继承要有所区别)。
D,接口可以继承其他的接口,并添加新的属性和抽象方法。
E,在类中实现接口的方法时必须加上public修饰符。
接口和抽象类的区别:
(1)相同点
A,两者都是抽象类,都不能实例化。
B,interface实现类及abstrct class的子类都必须要实现已经声明的抽象方法。
(2)不同点
A,interface实现,要用implements,而abstract class的实现,要用extends。
B,一个类可以实现多个interface,但一个类只能继承一个abstract class。
C,interface强调特定功能的实现,而abstract class强调所属关系。
D,尽管interface实现类及abstrct class的子类都必须要实现相应的抽象方法,但实现的形式不同。
E,interface是完全抽象的,只能声明方法,而且只能声明pulic的方法,不能声明private及protected的方法,不能定义方法体,也不能声明实例变量。
Q:String、StringBuffer和StringBuilder的区别
String:字符串常量 。StringBuffer 与 StringBuilder是字符缓冲变量。StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,只是StringBuffer中的方法大都采用了synchronized 关键字进行修饰,因此是线程安全的,而StringBuilder没有这个修饰,可以被认为是线程不安全的。StringBuilder 是在JDK1.5才加入的。
注意:从JDK1.5开始,带有字符串变量的连接操作(+),JVM 内部采用的是 StringBuilder 来实现的,而之前这个操作是采用 StringBuffer 实现的。
1、String类型的字符串对象是不可变的,一旦String对象创建后,包含在这个对象中的字符系列是不可以改变的,直到这个对象被销毁。
2、StringBuilder和StringBuffer类型的字符串是可变的,不同的是StringBuffer类型的是线程安全的,而StringBuilder不是线程安全的
3、如果是多线程环境下涉及到共享变量的插入和删除操作,StringBuffer则是首选。如果是非多线程操作并且有大量的字符串拼接,插入,删除操作则StringBuilder是首选。毕竟String类是通过创建临时变量来实现字符串拼接的,耗内存还效率不高,怎么说StringBuilder是通过JNI方式实现终极操作的。
总的来说,三者在执行速度方面的比较:StringBuilder > StringBuffer > String。
Q:String a=""和String a=new String("")的的关系和异同?
1. String是一个对象。 因为对象的默认值是null,所以String的默认值也是null;但它又是一种特殊的对象,有其它对象没有的一些特性。
2. new String()和new String(“”)都是申明一个新的空字符串,是空串不是null;
先简单引入常量池这个简单的概念。 常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。
用new String() 创建的字符串不是常量,不能在编译期就确定,所以new String() 创建的字符串不放入常量池中,它们有自己的地址空间。
5. 关于equals()和==:
这个对于String简单来说就是比较两字符串的Unicode序列是否相当,如果相等返回true;而==是比较两字符串的地址是否相同,也就是是否是同一个字符串的引用。
java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(==),比较的是他们的值。 2.复合数据类型(类)
当他们用( == )进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。 对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的,因为Object的equals方法也是用双等号( == )进行比较的,所以比较后的结果跟双等号(==)的结果相同。
Q:装箱、拆箱什么含义?
Java 中装箱和拆箱指的是基本数据类型和包装类型的自动相互转换,他为开发者提供了方便。开发人员也可以不使用它,而手动的进行类型转换。这个类型转换在编译阶段。
Q:int和Integer的区别?
int与integer的区别从大的方面来说就是基本数据类型与其包装类的区别:
int 是基本类型,直接存数值,而integer是对象,用一个引用指向这个对象
Q:遇见过哪些运行时异常?异常处理机制知道哪些?
当一个程序出现错误时,可能是以下三种错误:
语法错误:如缺少必要的标点符号、关键字输入错误、数据类型不匹配等,在编译器对程序进行编译的过程中,会把检测到的语法错误以提示的方式列举出来,故又称为编译错误。
运行时错误:如空指针异常,数组越界,除数为零、数据库连接失败等,迫使程序终止,有特定的发生条件。
逻辑错误:在语法上是有效的,但是在逻辑上是错误的,此类问题不好调试。
这里说的Java异常处理机制主要是指处理运行时错误。
a.Throwable继承层次结构,可见分成两大类Error和Exception。
Error
(错误):指程序无法恢复的异常情况,表示运行应用程序中较严重的问题。
- 发生于虚拟机自身、或者在虚拟机试图执行应用时,如Virtual MachineError(Java虚拟机运行错误)、NoClassDefFoundError(类定义错误)。
- 属于不可查异常,即不强制程序员必须处理,即使不处理也不会出现语法错误。
Exception
(异常):指程序
有可能恢复的异常情况,表示程序本身可以处理的异常。又分两大类:
-
RuntimeException
- (运行时异常):由程序自身的问题导致产生的异常。
- 如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)。
- 属于不可查异常。
- 非运行时异常:由程序外部的问题引起的异常。
- 除了RuntimeException以外的异常,如FileNotFoundException(文件不存在异常)。
-
属于可查异常,即强制程序员必须进行处理,如果不进行处理则会出现语法错误。
b.异常处理机制
(1)捕捉异常:由系统自动抛出异常
- try 捕获异常:用于监控,若发生异常,会抛出异常类所产生的对象并立刻结束执行,并转向异常处理catch块。
catch
处理异常:若抛出的异常对象属于catch内所定义的异常类,则进入catch中的对应代码段继续运行程序,反之进入finally块。常用方法:
- e.getMessage():返回异常对象的一个简短描述
- e.toString():获取异常对象的详细信息
- e.printStackTrace():在控制台上打印异常对象和它的追踪信息
finally
最终处理:无论是否捕获或处理异常,finally块里的语句都会被执行。在以下4种特殊情况下,finally块才不会被执行:
- 在finally语句块中发生了异常
- 在前面的代码中用了System.exit()退出程序
- 程序所在的线程死亡
- 关闭CPU
try {
// 可能会发生异常的程序代码
} catch (异常类1 异常变量) {
// 捕获并处理try抛出的异常类型Type1
} catch (异常类2 异常变量) {
// 捕获并处理try抛出的异常类型Type2
} finally {
// 无论是否发生异常,都将执行的语句块
}
注意:
- 一个try、catch、finally之间不能插入其它代码
- catch可有多个,try和finally只能有一个
- try后面必须至少跟着catch和finally其中的一个
(2)抛出异常:在方法中将异常对象显性地抛出,之后异常会沿着调用层次向上抛出,交由调用它的方法来处理。
- throws:声明抛出的异常,位置在方法名后、异常类型前
- throw:抛出异常,一般在方法体内部
(3)自定义异常:继承Execption类或其子类,实现步骤如下:
- 声明自定义异常类并继承Exception,可重写方法如getMessage()
- 在方法头用throws声明该方法可能抛出的异常
- 在方法体的适当位置创建自定义异常类对象,并用throw将异常抛出
- 调用该方法时,对可能产生的异常进行捕获,并处理异常
//1.自定义的异常类
class MyException extends Exception {
String message;
public MyException(String ErrorMessagr) {
super(ErrorMessagr) ;
}
public String getMessage() {
return message;
}
}
public class Demo {
public static void main(String[] args) {
//4.调用方法时捕获和处理
try {
test();
} catch (MyException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
//2.在方法头声明可能出现的异常
public static void test() throws MyException{
try {
int i = 10/0;
System.out.println("i="+i);
} catch (ArithmeticException e) {
//3.在适当情况下抛出异常
throw new MyException("This is MyException");
}
}
}
Q:什么是反射,有什么作用和应用?
Java基础之泛型&反射
a.泛型
含义:是JDK1.5的新特性,本质是参数化类型,即所操作的数据类型被指定为一个参数,使用时通过传参来指定具体的类型。
好处:安全简单。具体体现在提供编译时的强类型检查,而不用等到运行;可避免类类型强制转换;增强代码可读性。
//不使用泛型需要强制转换
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0)
//使用泛型可避免强制转换
List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0);
以上例子也能看到在集合类使用泛型的情况很普遍,而且相比于数组具有动态的特点。
-
类型
:通过创建位置的不同,分可为
泛型类:
public class 类名<泛型类型1,…>
泛型方法:
public <泛型类型1,…> 返回类型 方法名(泛型类型1 参数名1,…)
泛型接口:
public interface 接口名<泛型类型1,…>
下面分别举例说明。
//泛型类:把泛型定义在类上
public class ObjectTool<T> {
private T obj;
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
}
//测试
public class ObjectToolDemo {
public static void main(String[] args) {
ObjectTool<String> ot1 = new ObjectTool<String>();
ot1.setObj(new String("Jiwenjie"));
System.out.println("姓名是:" + ot1.getObj()); //姓名是:Jiwenjie
ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
ot2.setObj(new Integer(21));
System.out.println("年龄是:" + ot2.getObj()); //年龄是:21
}
}
//泛型方法:把泛型定义在方法上
public class ObjectTool {
public <T> T show(T t) {
if (t != null){
return t;
}else{
return null;
}
}
//测试
public class ObjectToolDemo {
public static void main(String[] args) {
ObjectTool ot = new ObjectTool();
System.out.println(ot.show("Jiwenjie"));//Jiwenjie
System.out.println(ot.show(21));//21
}
}
//泛型接口:把泛型定义在接口上
public interface ObjectTool<T,U> {
void show(T t,U u);
}
class ObjectToolTest implements ObjectTool<String,Date> {
@Override
public void show(String str,Date date) {
System.out.print(str);
System.out.print(date);
}
}
//测试
public class ObjectToolDemo {
public static void main(String[] args) {
ObjectToolTest test = new ObjectToolTest();
test.show("Hello",new Date());//Hello当前时间
}
}
- 泛型变量的类型限定:使用extends关键字,限定的是形式参数
如public class ObjectTool<T extends Number>表示只接受Number类或其子类的参数
- 通配符?的边界限定
:并配合
extends
和
super
- 关键字,限定的是
实际参数- 未受限List<?> :等效于List<? extends Object>
- 上边界限定List<? extends Number> :表示不确定参数类型,但一定是Number类或其子类的类型
- 下边界限定List<? super Number> :表示不确定参数类型,但一定是Number类或其父类的类型
如 List<? extends Number> list =new ArrayList<Integer>();表示创建元素对象都是Integer的List
- 泛型擦除:清除泛型类型参数的相关信息,并且在必要的时候添加类型检查和类型转换的方法。即泛型java代码->普通java代码
//擦除前
class Pair<T> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
//擦除后
class Pair {
private Object value;
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
使用限制:
//不能用基本类型实例化泛型
Pair<int, char> p = new Pair<>(8, 'a'); // error
Pair<Integer, Character> p = new Pair<>(8, 'a'); // ok
//不能用static修饰泛型类型
public class MobileDevice<T> {
private static T os; // error
}
//不能对参数化类型使用Casts,除非是*通配符类型
List<Integer> li = new ArrayList<>();
List<?> list = li; // ok
List<Number> ln = (List<Number>) li; // error
//不能对参数化类型使用instanceof,除非是*通配符类型
public static <E> void rtti(List<E> list) {
if (list instanceof ArrayList<Integer>) { // error
}
if (list instanceof ArrayList<?>) { // OK
}
}
//不能创建参数化类型的数组
ArrayList<String>[] arrayOfList = new ArrayList<String>[3]; // error
//不能创建、捕捉或抛出参数化类型的对象
class MathException<T> extends Exception {} // error
class QueueFullException<T> extends Throwable {} // error
public static <T extends Exception, J> void execute(List<J> jobs) {
try {
} catch (T e) { // error
}
}
//不能重载参数类型为相同原始类型的方法,因为擦除后是一样的
public class Example { // error
public void print(List<String> list) {}
public void print(List<Integer> list) {}
}
重点重点:
b.反射
含义:在运行状态中,对于任意一个类都能知道它的所有属性和方法,对于任何一个对象都能够调用它的任何一个方法和属性。
功能
:动态性
- 在运行时判断任意一个类所具有的属性和方法
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时调用任意一个对象的方法
- 生成动态代理
java.lang.Class
:实现反射的
基础
-
原因
JVM每创建一个类都会产生一个对应
Class
对象,并把它保存在同名.class
文件。有关类加载机制Java反射包
java.lang.reflect
中的所有类都没有public
构造方法,只能通过Class类获得这些类的实例
-
获取Class对象的方法
.class
:通过类的类型,基本类型可以使用Object.getClass()
:通过对象实例,注意基本数据类型无法使用Class.forName()
:通过类的全限定名,注意基本数据类型无法使用
Class c1 = Test.class;
Class c2 = test.getClass();// test是Test类的一个对象
Class c3 = Class.forName("com.catchu.me.reflect.Test");
java.lang.reflect.Member
- :反射操作的对象。提供三个实现类可在运行时改变对象状态:
- Constructor :对应类成员中的构造函数
- Field :对应类成员中的变量
- Method :对应类成员中的方法
在Class提供多种方法可以获取给定类的Constructor、Field和Method,方法如下图
性能问题。因为反射是在运行时而不是在编译时,所有不会利用到编译优化,同时因为是动态生成,因此,反射操作的效率要比那些非反射操作低得多。
安全问题。使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如Applet,那么这就是个问题了。
代码问题。由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
Q:什么是内部类?有什么作用?静态内部类和非静态内部类的区别?
某种程度上,公开的静态的内部类就相当于一个普通的类。静态内部类相对于外部类来说,仅仅只是包含关系,缩小了命名空间,完整类名中多了一个外部类的名称。本质上是两个独立的类,JVM 不知道他们的包含关系。
(1)静态内部类:它相当于外部类的静态成员一样,使用 static 修饰的内部类,它隶属于外部类,使用起来相当于一个独立的外部类。
(2)成员内部类:它相当于外部类普通的成员一样,隶属于外部类的具体对象,在定义它的时候,需要先创建外部类对象,之后在创建它的实例。
(3)局部内部类:它定义在一个方法的方法体中,它往往仅仅作为方法短暂使用,只能访问使用 final 修饰的局部变量。
(4)匿名内部类:它也是定义在方法体中,但是没有一个具体的名字,具有强大的灵活性,工作本质和局部内部类类似。
Q:final、finally、finalize()分别表示什么含义?
Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。
- final类不能被继承,没有子类,final类中的方法默认是final的。
- final方法不能被子类的方法覆盖,但可以被继承。
- final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
- final不能用于修饰构造方法。
注意:父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final类型的。
finally
用于异常捕获中的处理部分。
finalize:
finalize是方法名,java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是在垃圾收集器确认一个对象没有被引用时对这个对象调用的。它是在Object类中定义的,因此,所有的类都继承了它。子类覆盖finalize()方法已整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。
Q:Object有哪些公用方法?
(1)clone 方法,实现对象的浅复制。只有实现 Cloneable 接口才可以调用该方法。
(2)getClass 方法,用于获得运行时类型
(3)toString 方法,一般在子类中有重写,使用的比较多
(4)finalize 方法,该方法用于释放资源。因为无法确定该方法什么时候会调用,所以很少使用。
(5)equals 方法,一般来说 equals 和 == 是不一样的,但是在 Object 中两者是一样的。子类一般都要重写这个方法。
(6)hashCode 方法,用于哈希查找,可以减少在查找中使用 equals 的次数,重写了 equals 方法一般都要重写 hashCode 方法。这个方法在一些具有哈希功能的 Collection 中可以用到。
(7)wait 方法,就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait 方法一直等待,直到获得锁或者被中断。wait 设定一个超时间隔,如果在规定的时间内没有获得锁就返回。
(8)notify 方法,唤醒在该对象上等待的某个线程
(9)notifyAll 方法,该方法唤醒在该对象上等待的所有线程。