Java面试总结——基础篇

Java基础篇


  • JDK、JRE和JVM的关系
    JDK是java Development Kit,是Java程序的开发工具包,包含JRE和开发人员使用的开发工具。
    JRE是Java Runtime Environment,是Java程序的运行环境,包含了JVM和运行时所需要的核心类库。
    JVM是Java Virtual Machine,是java技术的核心。
    JDK、JRE、JVM的关系

  • java8大基本数据类型
    整型 byte(1) short(2) int(4) long(8)
    浮点型 float(4) double(8)
    逻辑型 boolean
    字符型 char(2)
    引用数据类型包括:类、接口、数组,引用数据类型占用4个字节
    String是final修饰的Java类,不可继承,属于引用数据类型

  • 为什么byte的取值范围是-128~127
    byte类型占1个字节,1字节=8bit,bit是描述电脑数据量的最小单位,在二进制中,一个0或者一个1就占用了一个bit,总共8bit,其中0代表正数,1代表负数
    byte最大取值范围是01111111=127
    byte最小取值范围是10000000=-128

  • java的特性之一
    跨平台性:
    java程序由即时编译器编译成字节码文件(.class),由java虚拟机(JVM)翻译成特定平台下的机器指令,具有“一次编译,到处运行”的特点。

  • Java的三大特点:继承、封装、多态

  • 访问控制权限修饰符
    public:公开的,全部都可以访问
    protected:受保护的,可以访问本类中、同包下以及子类的方法
    default:默认的,可以访问本类中、同包下的方法
    private:私有的,只可以在本类中访问

  • 重写和重载的区别(重点)
    重写(Override):方法名、参数列表、返回值类型都相同,根据需求只修改方法体中的代码,把原来的父类方法覆盖掉,同时继承父类方法,使用super.可以访问父类中的属性和方法;子类方法的访问修饰符权限要大于父类的(public>protected>default>private);重写不能抛出新的异常。
    总结:当子类继承了父类的方法,传入相同的参数,但程序做出了区别与父类方法的响应,并且还可以获取父类方法中的属性,体现了动态的多态性。
    重载:重载是在同一个类中定义多个同名方法,方法名相同,访问修饰符可以相同也可以不同,参数列表的参数个数和类型顺序都不同,并与返回值无关。
    (因此不能通过返回值来判断两个方法是否构成重载)
    总结:调用方法是通过传入的参数个数和类型的不同,由程序去判断执行哪个方法,这体现了Java的多态性

  • Object类
    所有类的基类。
    1.toString()方法
    返回一个Java对象的字符串表现形式

    //源代码上toString的默认实现
    public String toString(){
    	return this.getClass().getName()+"@"+Integer.toHexString(hashCode()); 
    	//返回的是 类名@对象的内存地址转换为十六进制的形式
    }
    

    JDK1.8的API文档中提到 一般建议重写toString()方法

    2.finalize()方法

    //源代码
    protected void finalize () throws Throwable();
    

    这个方法不需要程序员去手动调用,JVM的垃圾回收器负责调用这个方法,当一个Java对象即将被回收的时候,垃圾回收器会调用finalize()方法。
    如果Java虚拟机并未面临内存消耗的情况,他是不会浪费时间去执行垃圾回收的以恢复内存,毕竟垃圾回收时是会影响程序的运行效率的
    finalize()方法是一个为程序员准备的时机——垃圾销毁的时机,在垃圾销毁时想要执行一段代码的话,可以写在finalize()方法中。

    3.hashCode()方法

     //源码 native方法 底层调用C++程序
    	 public native int hashCode();
    

    hashCode()方法返回的Java对象的虚拟内存地址

  • this和super关键字
    this
    this是一个引用,this的内存地址指向了自身
    this可以出现在实例方法中(没有static修饰的方法),代表所在方法对当前对象的引用,一般可省略
    this可以用来区分实例变量和局部变量 构造方法中的 this.id=id
    this可以在构造方法中通过当前的构造方法调用其他的构造方法 this(实参)的格式,并且只能现在第一行
    super
    super可以访问父类中定义的属性
    super可以调用父类中的成员方法
    super可以在子类构造方法中调用父类构造方法,也要放在第一行
    在多层继承中,super可以访问到直接或间接的父类
    注意:通过this或者是super调用构造器,只能使用一个,因为他们的使用都必须放在首行
    在这里插入图片描述

  • static(静态)关键字
    static修饰的方法是静态方法,没有static修饰的方法是实例方法;
    *访问静态方法用 “类名.”,访问实例方法用 “引用.”
    判断方法使用需要用static修饰,要看该方法是否需要对象来执行,需要对象来执行的话就不加static属于实例方法,通过“引用.”的方式调用 *

    static修饰的变量是静态变量,没有static修饰的方法是实例变量;
    *访问静态变量用 “类名.”,访问实例变量用 “引用.” *

    静态代码块

    static{
    	//静态代码块在类加载的时候执行,且只执行一次
    	}
    
  • final关键字
    final修饰的类:为最终类,不被继承
    final修饰的方法:不能被重写
    final修饰的变量:叫常量,赋初始值之后不可改变

  • 抽象类abstract
    abstract修饰一个方法时,这个方法叫抽象方法;
    abstract关键字修饰一个类时,这个类叫抽象类;
    含有抽象方法的类必须声明为抽象类;
    抽象类不能被实例化;
    抽象方法只有方法的声明,没有方法的实现,抽象类是用来被继承的,由子类重写父类方法,并提供方法体;
    public abstract int abstractMethod(int a) ;
    子类继承抽象类之后,必须重写抽象类里的全部抽象方法;

    不能用abstract修饰属性、私有方法、构造器、静态方法、final的方法(final方法不能被继承,抽象方法与要重写)

  • 接口interface
    接口是特殊的抽象类;
    接口中的方法都是抽象方法 ;
    接口中只有抽象方法和常量;
    接口中抽象方法的public abstract可省略,接口中常量的public static final可省略;
    JAVA的继承特点
    一个接口可以继承多个接口(多继承)interface A extends B,C{ }
    一个类可以实现多个接口 interface A implements B,C{ }
    一个类只能继承一个类 classB Extends classA
    Java类是单继承的
    Java接口可以继承多个接口

  • = =和equals的区别
    = = 比较基本数据类型:值是否相同
    = = 比较引用数据类型:引用地址是否相同
    equals()只能比较引用类型:是否指向同一个对象
    * 当equals()比较的是File、String、Date、Wapper(包装类)时,比较的时内容和类型,因为在这些类中重写了equals()方法 ;equals继承了Object类,可以重写equals()方法*

  • 两个对象的hashCode相同,equals()也一定为 true吗?
    不对,两个对象的 hashCode()相同,equals()不一定 true。

  • java 中操作字符串都有哪些类?
    操作字符串:String、StringBuffer、StringBuilder

    StringBuilder和StringBuffer的区别
    String:底层是byte[]数组 但是final修饰的 private final byte[] value;是不可变的,每次进行String字符串拼接都会产生一个新的String对象
    StringBuilder和StringBuffer底层是也是`byte[] value;
    StringBuilder和StringBuffer都是可变字符序列,底层也是数组扩容问题。
    StringBuffer:线程安全的(因此开销也大)。
    StringBuilder:非线程安全的,效率高。

    摘自《JDK1.8API文档》
    StringBuffer上的主要操作就是append和insert方法,可重载这些方法,已接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将这写字符串的字符添加或插入到字符串的缓冲区中。append方法始终将这些字符串添加到缓冲区的末端;insert方法则在指定的点添加字符。

    如何优化StringBuffer性能
    StringBuffer实际上是用byte[]数组进行存储,并且初始化容量是16,在存储字符的时候是自动扩容的(通过数组拷贝这个方法arraycope)。在创建StringBuffer时尽可能给定一个初始化容量,尽量减少底层代码进行数组扩容的次数,预估记给一个合适的初始化容量(数组长度一旦确定不可更改,只能进行扩容)可以提高程序效率。

    //StringBuilder用法同下
    //指定初始化容量的StringBuffer对象(字符串缓冲区对象)
    StringBuffer sb = new StringBuffer(50);
    //append追加字符串代替拼接字符串
    sb.append("hello");
    sb.append("world");
    System.out.println(sb);
    //Output:helloworld
    

    String、StringBuilder、StringBuffer三者的执行效率:
    StringBuilder > StringBuffer > String
    当然这个是相对的,不一定在所有情况下都是这样。
    比如String str = “hello”+ "world"的效率就比 StringBuilder st = new StringBuilder().append(“hello”).append(“world”)要高。因此,这三个类是各有利弊,应当根据不同的情况来进行选择使用:
    当字符串拼接操作或者改动较少的情况下,建议使用 String str="hello"这种形式;
    当字符串拼接操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer。

  • break、return、continue的区别
    break跳出当前循环;
    return种植当前方法;
    continue跳出这次循环,直接进行下次循环;

  • String(重点)
    String类中的常用方法
    String.charAt():返回指定索引处的char值
    String.contains():判断前面字符串是否包含后面的字符串
    String.equals():比较引用类型,比较的是内容和引用,比较Date,String,包装类的时候只比较内容
    String.equalsIgnoreCase():比较两个字符串忽略大小写
    String.indexOf(String s):返回当前字符串中s第一次出现的下标
    String.lastIndexOf(String s):返回当前字符串中s最后一次出现的下标
    String.isEmpty():判断某个字符串是否为空
    String.length():返回字符串方法
    String.replace(char oldChar,char newChar):用new char替换到所有old char所在的位置上,返回一个新的字符串
    String.split():根据给定的字符串(或正则表达式)把字符串拆分,返回String一个数组
    String.subString(int beginIndex):从beginIndex的位置开始往后截取到最后(下标从0开始)
    String.subString(int beginIndex,int endIndex):从beginIndex的位置开始往后截取到endIndex-1的位置(左开右闭)
    String.toCharArray():字符串转换成char[]数组
    String.toLowerCase():将String所有的字符转换成小写
    String.toUpperCase():将String所有的字符转换成大写
    String.trim():去除字符串中的空白
    String.valueOf():String类中唯一一个静态方法,不需要new新对象,把一个非字符串转成字符串

  • String的内存分配问题(相关面试题)

    String s1 = "a";
    String s2 = "b";
    String s3 = "ab";
    String s4 = "a" + "b";
    String s5 = "a" + s2; //拼接符号前或后出现了变量s2,相当于在堆中new String(),所以s5和s3的内存地址不同
    String s6 = s1 + s2; //s6:StringBuilder.append("a").append("b").toString()相当于是在堆中创建个新对象new String("ab") 
    String s7 = new String("a") + new String("b");//相当于new String("ab")
    String s8 = s7.intern();
    
    -----------------------------//在JDK1.8的环境中
    System.out.println(s3 == s4); //true  s3和s4是一样的,是存储在方法区的字符串常量池中的(串池中的对象唯一且不重复)
    System.out.println(s3 == s5); //false 但是s3.equals(s5)是true
    System.out.println(s3 == s6); //false s6在堆中
    System.out.println(s3 == s7); //false
    System.out.println(s3 == s8); //true
    /*
    解释后两个比较结果
    String.intern()方法:
    在JDK1.7/1.8中:将字符串对象尝试放入串池中,如果串池中有则不会放入,如果没有则放入,并把串池中的对象返回。
    在JDK1.6中:将字符串对象尝试放入串池中,如果串池中有则不会放入,如果没有则复制一份放入,并把串池中的对象返回。
    所以在这里串池中已经有“ab”(s3)了,则s7没有被放入串池还是在Java堆中,而返回的s8就是串池中的“ab”
    */
    

    通过字节码文件分析new String(“a”) + new String(“b”)过程中创建了几个对象?
    6个。
    第一个:拼接字符串时首先会new StringBuilder()
    第二个:常量池中的"a"
    第三个:堆中new String(“a”)
    第四个:常量池中的"b"
    第五个:堆中new String(“b”)
    第六个:堆中new String(“ab”)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值