第一章 java 基础......................................................................... 16
1.1.6. short s1 = 1; s1 = s1 + 1;有错吗short s1 = 1; s1 += 1;有错吗................................................................ 17
1.1.12. ==和 equals 的区别................................................................ 20
JDK:Java Development Kit 的简称,Java 开发工具包,提供了 Java 的开发环境和运行环境。JRE:Java Runtime Environment 的简称,Java 运行环境,为 Java 的运行提供了所需环境。 具体来说 JDK 其实包含了 JRE,同时还包含了编译 Java 源码的编译器 Javac,还包含了很多 Java 程序调试和分析的工具。简单来说:如果你需要运行 Java 程序,只需安装 JRE 就可以了,如果你需要编写 Java 程序,需 要安装 JDK。 |
String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,而 String 属于引用数据类型。 |
1、Integer 是 int 的包装类,int 则是 java 的一种基本数据类型2、Integer 变量必须实例化后才能使用,而 int 变量不需要 3、Integer 实际是对象的引用,当 new 一个 Integer 时,实际上是生成一个指针指向此对象;而 int 则是直接存 |
储数据值 4、Integer 的默认值是 null,int 的默认值是 0 |
答案: 用移位运算 int a=2<<3; a 就是 2 乘以 8 最后结果是 16 这是最省内存 最有效率的方法解释: 这个方法确实高效率的。我来解释一下: 2 的二进制是 10 在 32 位存储器里面是 0000 0000 0000 0010 左移三位后变成 0000 0000 0001 0000 也就是 16 同理: 2 << 3(左移 3 位相当于乘以 2 的 3 次方,右移 3 位相当于除以 2 的 3 次方) |
不正确。3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄 化)会造成精度损失,因此需要强制类型转换 float f =(float)3.4; 或者写成 float f =3.4F。 |
对于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 类型,因此 s1+1 运算结果也是 int 型,需要强制转换类型才能 赋值给 short 型。而 short s1 = 1; s1 += 1;+=操作符会进行隐式自动类型转换,是 Java 语言规定的运算符; Java 编译器会对它进行特殊处理,因此可以正确编译。因为 s1+= 1;相当于 s1 = (short)(s1 + 1). |
为了能够将这些基本数据类型当成对象操作,Java 为每一个基本数据类型都引入了对应的包装类型(wrapper class),int 的包装类就是 Integer,从 Java 5 开始引入了自动装箱/拆箱机制,使得二者可以相互转换。Java 为每个原始类型提供了包装类型: |
原始类型: boolean,char,byte,short,int,long,float,double 包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double 自动装箱:基本数据类型自动转换为包装类型 自动拆箱:包装类型自动转换为基本数据类型 |
Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加 0.5 然后进行下取整。 |
在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。从 Java 5 开始,Java 中引入了枚举类型,expr 也可以是 enum 类型,从 Java 7 开始,expr 还可以是字符串(String),但是长整型(long)在目前所 有的版本中都是不可以的。 |
在最外层循环前加一个标记如 A,然后用 break A;可以跳出多重循环。(Java 中支持带标签的 break 和 continue 语句,作用有点类似于 C 和 C++中的 goto 语句,但是就像要避免使用 goto 一样,应该避免使用带标签的 break 和 continue,因为它不会让你的程序变得更优雅,很多时候甚至有相反的作用) |
方式一:开发中常用的,使用中间变量 public class SwapDemo{ public static void main(String[] args) { int i = 10; int j = 20; int temp; temp = i; //i = 10; j = 20; temp = 10; i = j; //i = 20; j = 20; temp = 10; j = temp; //i = 20; j = 10; temp = 10; |
System.out.println("i=" + i + ";j=" + j);
// "i=20;j=10"
}
}
方式二:不使用中间变量的,“和”实现
public class SwapDemo{
public static void main(String[] args) { int i = 10;
int j = 20;
i = i + j; //i = 30; j = 20; j = i - j; //i = 30; j = 10; i = i - j; //i = 20; j = 10;
System.out.println("i=" + i + ";j=" + j);
// "i=20;j=10"
}
}
方式三:面试中使用的,按位亦或 “^”
public class SwapDemo{
public static void main(String[] args) { int i = 10;
int j = 20;
System.out.println("i=" + i + ";j=" + j);
// "i=20;j=10"
}
}
方式四:一句话实现交换
public class SwapDemo{
public static void main(String[] args) { int i = 10;
int j = 20;
j = ( i + j ) - ( i = j ); System.out.println("i=" + i + ";j=" + j);
// "i=20;j=10"
}
}
==号在比较基本数据类型时比较的是值,而用==号比较两个对象时比较的是两个对象的地址值; equals()方法存在于 Object 类中,默认效果和==号的效果一样,也是比较的地址值,然而,Java 提供的所有类中, 绝大多数类都重写了 equals()方法,比如 string,integer 等,重写后的 equals()方法一般都是比较两个对象的值 。 |
1、hashCode()方法的作用是获取对象的哈希值,获取对象每个属性的哈希值,最终返回对象的哈希值; 2、equals()方法默认比较的是两个对象的地址值,而一般使用需要进行重写,比较对象每个属性的 hash 值是否一致,若完全两个对象的每个属性的 hash 值都相同则认为是同一个对象,若有一个属性不一致则认为两个对象不相同。 3、一般来说 hashCode 相同的两个对象不见得是同一个对象,有可能发生哈希碰撞现象,需要重写 hashCode()方 法,在方法中,每次计算 hash 值时, |
不对,两个对象的 hashCode() 相同,equals() 不一定 true。 hashCode()只是计算对象属性的哈希值,有可能属性不一致,但是刚好哈希值一样,发生哈希碰撞,比如 5+2=7, 4+3=7,但是这两个 7 并不是同一个 7. |
问题:
Integer i = 100; Integer j = 100; System.out.print(i == j); //true Integer i = 128; Integer j = 128; |
System.out.print(i == j); //false |
答案:
Integer 类型维护了一个整数常量池,取值范围-128-127。 创建 Integer 对象时,如果数值在范围内,直接从常量池中获取,否则需要开辟空间创建新的对象。 |
char 类型可以存储一个中文汉字,因为 Java 中使用的编码是 Unicode(不选择任何特定的编码,直接使用字符在 字符集中的编号,这是统一的唯一方法),一个 char 类型占 2 个字节(16 比特),所以放一个中文是没问题的。 |
1、final 修饰的类叫最终类,该类不能被继承。 2、final 修饰的方法不能被重写。 3、final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。 |
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。 泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。 |
1,类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话, 还存在于代码注释中)。 2,消除强制类型转换。 泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。 3,潜在的性能收益。 泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话, 程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。所有工作都在编译器 |
中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。 |
length(): 求 字 符 串 的 长 度 indexOf():求某个字符在字符串中的位置charAt():求一个字符串中某个位置的值equals():比较两个字符串是否相同 replace():将字符串中的某些字符用别的字符替换掉。形如 replace(“abc”,”ddd”);字符串中的 abc 将会被 ddd 替换掉。 split():根据给定正则表达式的匹配拆分此字符串。形如 String s = "The time is going quickly!"; str1=s.split(" "); substring():输出一个新的字符串,它是此字符串中的子串,形如 substring(3,7);它将字符串中的第四个第五个第六个输出。 trim():将字符串开头的空白(空格)和尾部的空白去掉。 format():使用指定的语言环境、格式字符串和参数返回一个格式化字符串。toLowerCase():将字符串中所有的大写改变成小写 toUpperCase():将字符串中所有的小写改变为大写 getBytes():获取字符串字节数组 |
intern()方法会首先从常量池中查找是否存在该常量值,如果常量池中不存在则现在常量池中创建,如果已经存在 则直接返回。 比如 String s1=”aa”; String s2=s1.intern(); System.out.print(s1==s2);//返回 true |
不一样,因为内存的分配方式不一样。String str="i"的方式,Java 虚拟机会将其分配到常量池中;而 String str=new String("i") 则会被分到堆内存中。 |
相同点:三个类都是处理字符串的类; 不同点:String 是长度不可变字符串,StringBuffer 和 StringBuilder 是长度可变的字符串,维护一个缓冲区。 StringBuilder 线程不安全,效率高;StringBuffer 线程安全,效率低; |
hashCode():计算对象成员的哈希值equals():判断对象是否相等clone():对对象进行 clone getClass():获取对象的 Class 字节码文件对象wait():线程阻塞,线程挂起等待notify(),notifyAll():线程唤醒,线程就绪,继续运行 toString():获取对象的信息,一般重写,默认返回地址值 |
1 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。 2.封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本 质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们 编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程 接口(可以想想普通洗衣机和全自动洗衣机的差别,明显全自动洗衣机封装更好因此操作起来更简单;我们现在使 |
用的智能手机也是封装得足够好的,因为几个按键就搞定了所有的事情)。 3.继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承 信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素 的重要手段(如果不能理解请阅读阎宏博士的《Java 与模式》或《设计模式精解》中关于桥梁模式的部分)。4.多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同 样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界 提供的服务,那么运行时的多态性可以解释为:当 A 系统访问 B 系统提供的服务时,B 系统有多种提供服务的方式, 但一切对 A 系统来说都是透明的(就像电动剃须刀是 A 系统,它的供电系统是 B 系统,B 系统可以使用电池供电或者用交流电,甚至还有可能是太阳能,A 系统只会通过 B 类对象调用供电的方法,但并不知道供电系统的底层实现是什么,究竟通过何种方式获得了动力)。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而 方法重写(override)实现的是运行时的多态性(也称为后绑定)。 |
允许不同类对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用)。主要有以下优点: 1、可替换性:多态对已存在代码具有可替换性 2、可扩充性:增加新的子类不影响已经存在的类结构 3、接口性:多态是超类通过方法签名,向子类提供一个公共接口,由子类来完善或者重写它来实现的。 4、灵活性 5、简化性 |
实现多态主要有以下三种方式:
|
接口的意义用三个词就可以概括:规范,扩展,回调。 |
抽象类的意义可以用三句话来概括: 为其他子类提供一个公共的类型 封装子类中重复定义的内容 定义抽象方法,子类虽然有不同的实现,但是定义时一致的 |
修饰符 |
当前类 |
同 包 |
子 类 |
其他包 |
|
public |
√ |
√ |
√ |
√ |
|
protected |
√ |
√ |
√ |
× |
|
default |
√ |
√ |
× |
× |
|
private |
√ |
× |
× |
× |
第一章 要有类的继承 第二章 要有方法的重写(子类继承父类并重写父类中已有的或抽象的方法) 第三章 对象造型(父类的引用指向子类的对象,这样同样的引用调用同样的方法会根据子类对象的不同而表现不同的行为) |
1、抽象类只能被单继承,但是接口可以多实现; 2、抽象类中有构造方法,需要对子类访问父类的成员进行初始化,接口中没有构造方法。 3、抽象类中即可以有普通成员变量也可以有常量,接口中变量全是常量,默认修饰符 public static final; 4、抽象类中既可以有抽象方法,也可以有普通方法,但是有有抽象方法的类必须定义为抽象方法;接口中的方 法只能定义为抽象方法,默认修饰符 public abstarct。 5、抽象类可以被抽象方法可以有 public,protected 和 default 等修饰,接口只能被 public 修饰 |
不能。重写只适用于实例方法,不能用于静态方法,而子类当中含有和父类相同签名的静态方法,我们一般称之为隐藏。 |
不可变对象指对象一旦被创建,状态就不能再改变。任何修改都会创建一个新的对象,如 String、Integer 及其它包装类。 |
重载(Overload):在同一个类中,方法名称相同,参数列表不同(参数类型,参数个数,参数名称),与返回值无关, 称之为重载; 重写(Override):子类中存在与父类中方法声明完全相同的方法,称之为方法重写; 方法重载只与方法名称和参数列表相关,与返回值无关,不能通过返回类型区分。 |
Throwable 类是所有异常或错误的超类,它有两个子类:Error 和 Exception,分别表示错误和异常。其中异常Exception 分为运行时异常(RuntimeException)和编译时时异常。 Error:一般是指 java 虚拟机相关的问题,如系统崩溃、虚拟机出错误、动态链接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断,通常应用程序无法处理这些错误 Exception 异常又分为两种: Exception:编译时异常,如果异常不处理,则代码无法编译。 RuntimeException:运行时异常,运行时发生,无需处理,对代码进行修改解决问题。 常见的运行时异常: 1、NullPointerException:空指针异常,调用了未经初始化的对象或者是不存在的对象。 2、ClassNotFoundException :指定的类不存在,这里主要考虑一下类的名称和路径是否正确即可 。 |
3、ArrayIndexOutOfBoundsException :数组下标越界异常,对数组时操作,调用的下标超过了数组的范围。4 、NoSuchMethodException:方法不存在错误。当应用试图调用某类的某个方法,而该类的定义中没有该方法的定义时抛出该错误。 5、FileNotFoundException:文件未找到异常,进行 IO 操作时,访问的文件不存在。 |
1、throws:throws 来告知调用程序此方法可能会抛出的异常,但是不会处理。调用方法可能会处理这些异常,或者同样用 throws 来将异常传给上一级调用方法。throws 关键字后可接多个潜在异常类名。 2、try-catch:try-catch 块捕获处理异常。在 try 代码块中,包含可能发生异常的代码,一旦发生异常,则抛出异常对象,会进入 catch 代码块,一个 try 块之后可以有多个 catch 子句,try-catch 块也能嵌套。每个 catch 块必须接受一个(且仅有一个)代表异常类型的异常对象参数,若 try 中抛出的异常和 catch 接收的异常类型一致,则进入对应的 catch 代码块。 3、try-catch 可以和 finally 结合使用,finally 代码块肯定会执行。 |
throw 语句用在方法体内,表示抛出异常对象,由方法体内的语句处理。throws 语句用在方法声明后面,表示抛出异常,由该方法的调用者来处理。 throws 主要是声明这个方法会抛出这种类型的异常,使它的调用者知道要捕获这个异常。throw 是当程序出现某种逻辑错误时主动抛出一个异常实例。 throw 与 throws 的比较 1、throws 出现在方法函数头;而 throw 出现在函数体。 2、throws 表示出现异常的一种可能性,并不一定会发生这些异常;throw 则是抛出了异常,执行 throw 则一定抛出了某种异常对象。 3、两者都是消极处理异常的方式,只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。 throws: public static void write() throws FileNotFoundException { FileInputStream fileInputStream=new FileInputStream("c"); } |
throw: String s = "abc"; if (s.equals("abc")) { throw new NumberFormatException(); } · |
NullPointerException 空指针异常ClassNotFoundException 指定类不存在NumberFormatException 字符串转换为数字异常IndexOutOfBoundsException 数组下标越界异常ClassCastException 数据类型转换异常FileNotFoundException 文件未找到异常NoSuchMethodException 方法不存在异常IOException IO 异常 SocketException Socket 异常 |
try-catch-finally 其中 catch 和 finally 都可以被省略,但是不能同时省略,也就是说有 try 的时候,必须 后面跟一个 catch 或者 finally。 |
finally 一定会执行,即使是 catch 中 return 了,catch 中的 return 会等 finally 中的代码执行完之后,才会执行。 |
final:是修饰符,如果修饰类,此类不能被继承;修饰方法,方法不能被重写;修饰变量,变量为常量,只能赋值 一次。 finally:是 try{} catch{} finally{} 最后一部分,表示不论发生任何情况都会执行,finally 部分可以省略,但如果 finally 部分存在,则一定会执行 finally 里面的代码。 |
finalize: 是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法。 |
类加载分为三个步骤:加载,连接,初始化;
生与所加载类对应的 Class 对象。加载完成后,Class 对象还不完整,所以此时的类还不可用。当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析
(将符号引用替换为直接引用)三个步骤。最后 JVM 对类进行初始化,包括:1)如果类存在直接的父类并且这个类还没有被初始化,那么就先初始化父类;2)如果类中存在初始化语句,就依次执行这些初始化语句。
JVM 自带的 Bootstrap 是根加载器,其他的加载器都有且仅有一个父类加载器。类的加载首先请求父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载。JVM 不会向Java 程序提供对Bootstrap 的引用。下面是关于几个类加载器的说明:
Bootstrap:一般用本地代码实现,负责加载 JVM 基础核心类库(rt.jar);
Extension: 从 java.ext.dirs 系统属性所指定的目录中加载类库, 它的父加载器是 Bootstrap; System:又叫应用类加载器,其父类是 Extension。它是应用最广泛的类加载器。它从环境变量 classpath 或者系统属性 java.class.path 所指定的目录中记载类,是用户自定义加载器的默认父加载器。