Android面试准备之Java基础

一、Java基础知识

1 什么是面向对象,谈谈你对面向对象的理解

对比面向过程,是两种不同的处理问题的角度,面向过程更注重事情的每一个步骤及顺序,面向对象更注重事情有哪些参与者、及各自需要做什么。

三大特性:封装、继承、多态

  • 封装:封装的意义,在于明确标识出允许外部使用的所有成员函数和数据项,内部细节对外部调用透明,外部调用无需修改或者关心内部实现。例:JavaBean
  • 继承:继承基类的方法,并做出自己的改变和/或扩展。子类共性的方法或者属性直接使用父类的,而不需要自己再定义,只需扩展自己个性化的。
  • 多态:基于对象所属类的不同,外部对同一个方法的调用,实际执行的逻辑不同。关键在于继承、方法重写,并且父类引用指向子类对象,但无法调用子类特有的功能。
父类类型 变量名 = new 子类对象;
变量名.方法名();

2 ==和equals比较

==对比的是栈中的值,基本数据类型是变量值,引用类型是堆中内存对象的地址
equalsobject中默认也是采用==比较,通常会重写

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是一种所有符号的编码,是一个符号集,它规定了符号的二进制代码,没有规定这个二进制代码应该如何存储。它造成的结果是:

  1. 出现了Unicode的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示Unicode。
  2. 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){
   
   ...}
}

匿名内部类的构造方法总结

  1. 编译器生成
  2. 参数列表包括:
    · 外部对象(定义在非静态域内)
    · 父类的外部对象(父类非静态)
    · 父类的构造方法参数(父类有构造方法且参数列表不为空)
    · 外部捕获的变量(方法体内有引用外部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[];
    ...
}

Stringfinal修饰的,不可变,每次操作都会产生新的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);
    }
    ...
}

                
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值