一、Java基础知识
1 什么是面向对象,谈谈你对面向对象的理解
对比面向过程,是两种不同的处理问题的角度,面向过程更注重事情的每一个步骤及顺序,面向对象更注重事情有哪些参与者、及各自需要做什么。
三大特性:封装、继承、多态
- 封装:封装的意义,在于明确标识出允许外部使用的所有成员函数和数据项,内部细节对外部调用透明,外部调用无需修改或者关心内部实现。例:
JavaBean - 继承:继承基类的方法,并做出自己的改变和/或扩展。子类共性的方法或者属性直接使用父类的,而不需要自己再定义,只需扩展自己个性化的。
- 多态:基于对象所属类的不同,外部对同一个方法的调用,实际执行的逻辑不同。关键在于继承、方法重写,并且父类引用指向子类对象,但无法调用子类特有的功能。
父类类型 变量名 = new 子类对象;
变量名.方法名();
2 ==和equals比较
==对比的是栈中的值,基本数据类型是变量值,引用类型是堆中内存对象的地址
equals:object中默认也是采用==比较,通常会重写
public class StringDemo {
public static void main(String args[]) {
String str1 = "Hello";
String str2 = new String("Hello");
String str3 = str2;
System.out.println(str1 == str2);//false
System.out.println(str1 == str3);//false
System.out.println(str2 == str3);//true
System.out.println(str1.equals(str2));//true
System.out.println(str1.equals(str3));//true
System.out.println(str2.equals(str3));//true
}
}
3 Java的char是两个字节,是怎么存UTF-8字符的
UTF-8、ASCII码、Unicode
- ASCII码
128个字符的编码,占用了一个字节(一个字节为8位256种状态)的后面7位,最前面的1位统一规定为0。
- Unicode
Unicode是一种所有符号的编码,是一个符号集,它规定了符号的二进制代码,没有规定这个二进制代码应该如何存储。它造成的结果是:
- 出现了Unicode的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示Unicode。
- Unicode在很长一段时间内无法推广。
- UTF-8、UTF-16
UTF-8是Unicode的实现方式之一。UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。对于英语字母,UTF-8编码和ASCII码是相同的。UTF-8最小单位为1个字节,UTF-16最小单位为2个字节,char用UTF-16存储。
一个utf-8数字占1个字节,一个utf-8英文字母占1个字节,少数汉字每个占用3个字节,多数占用4个字节。字符串长度不等于字符数(如emoji字符)
总结
- Java char不存储UTF-8的字节,而是UTF-16的
- Unicode是字符集,不是编码,作用类似于ASCII码
- Java String的length不是字符数
4 Java String可以有多长
- 字符串有多长是指字符数还是字节数
- 字符串有几种存在形式
- 字符串的不同形式受到何种限制
字符串有几种存在形式
- 栈
源文件:.java文件
`String longString = "aaa...aaa";`
字节码:.class文件
CONSTANT_Utf8_info{
u1 tag;
//0~65535实际存储65535个latin字符会报错,原因是编译器判断时用的是'<',kotlin可以存储65535
//非latin字符可以存储65535,因为编译器对于汉字的判断用'>'
u2 length;
u1 bytes[length];//最多65535个字节
}
存储在虚拟机方法区的常量池中。
- 堆
byte[] bytes = loadFromFile(new File("superLongText.txt"));
String superLongString new String(bytes);
受到虚拟机指令限制,字符数理论上限为Integer.MAX_VALUE,实际上限可能小于Integer.MAX_VALUE,如果堆内存较小,也会受到堆内存的限制。
总结
Java String字面量形式
- 字节码中CONSTANT_Utf8_info的限制
- Javac源码逻辑的限制
- 方法区大小的限制
Java String运行时创建在堆上的形式
- Java虚拟机指令newarray的限制
- Java虚拟机堆内存大小的限制
5 final有什么作用,为什么局部内部类和匿名内部类只能访问局部final变量,匿名内部类有什么限制
- 修饰类:表示类不可被继承
- 修饰方法:表示方法不可被子类覆盖
- 修饰变量:表示变量一旦被赋值就不可以更改,如果是引用类型的变量,初始化后不能再让其指向另一个对象,但是引用的值是可变的
public class FinalReferenceTest {
public static void main() {
final Person p = new Person(25);
p.setAge(24);//合法
p = null;//非法
}
}
当外部类的方法运行结束时,方法中的局部变量就销毁了,但是内部类对象可能还存在,这时内部类对象就会访问一个不存在的变量。为了解决这个问题,就将局部变量复制了一份作为内部类的成员变量,这样当局部变量死亡后,内部类访问的是局部变量的快照。所以为了保证局部变量和内部类的成员变量一致,需要将局部变量设置为final。
- 匿名内部类的名字
外部类+$N,N是匿名内部类的顺序
- 匿名内部类的构造方法
第一种情形:
public class Client {
public void run() {
InnerClass innerClass = new Outerclass().new InnerClass(){
...};
}
}
public class OuterClass {
public abstract class InnerClass {
abstract void test();
}
}
编译结果:
public class Client$1{
//非静态方法有自己的外部类实例引用,也有非静态父类的外部类实例引用
public Client$1(Client client, OuterClass outerClass){
...}
}
第二种情形:
public class Client {
public void run() {
InnerClass innerClass = new Outerclass().InnerClass(){
...};
}
}
public class OuterClass {
public interface InnerClass {
void test();
}
}
编译结果:
public class Client$1{
public Client$1(Client client){
...}
}
第三种情形(静态方法):
public class Client {
public static void run() {
InnerClass innerClass = new Outerclass().InnerClass(){
...};
}
}
public class OuterClass {
public interface InnerClass {
void test();
}
}
编译结果:
public class Client$1{
public Client$1(){
...}
}
捕获外部变量:
public class Client {
public static void run() {
final Object object = new Object();
InnerClass innerClass = new Outerclass().InnerClass(){
@Override
void test() {
System.out.println(object.toString());
}
};
}
}
public class OuterClass {
public interface InnerClass {
void test();
}
}
编译结果:
public class Client$1{
public Client$1(Object object){
...}
}
匿名内部类的构造方法总结
- 编译器生成
- 参数列表包括:
· 外部对象(定义在非静态域内)
· 父类的外部对象(父类非静态)
· 父类的构造方法参数(父类有构造方法且参数列表不为空)
· 外部捕获的变量(方法体内有引用外部final变量)
- Lambda转换(SAM类型):single abstract method,只能代替接口类型并只能有一个方法
总结
- 没有人类认知意义上的名字
- 只能继承一个父类或实现一个接口
- 父类是非静态的类型,则需父类外部实例来初始化
- 如果定义在非静态作用域内,会引用外部类实例
- 只能捕获外部作用域内的final变量
- 创建时只有单一方法的接口可以用Lambda转换
6 String、StringBuffer、StringBuilder区别及源码分析
- String
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
...
}
String是final修饰的,不可变,每次操作都会产生新的String对象。
例如String s = new String(“xyz”);的执行过程是,先在常量池中找xyz这个对象,如果没有,先在常量池中创建这个字符串对象,然后在堆中创建常量池中这个对象的拷贝对象,栈中的局部变量s再指向堆中的对象。所以,执行这个语句有可能产生一个(常量池已经有xyz)或两个(常量池中没有xyz)对象。
- StringBuilder/StringBuffer
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}
...
}

最低0.47元/天 解锁文章
2513

被折叠的 条评论
为什么被折叠?



