美文网首页
1.Java基础

1.Java基础

作者: Rinma | 来源:发表于2020-09-16 19:59 被阅读0次

题目来源于:https://www.bilibili.com/read/cv7046891

1.JDK和JRE有什么区别?

  • JDK:Java Development Lit,为Java开发工具包,提供包括编译器(javac)、开发工具(javadoc、jre、keytool、jconsole)和更多类库(tools.jar)等,JDK中包含JRE。
  • JRE:Java Runtime Environment,为Java程序运行时环境,包含Java虚拟机(JVM)、Java基础类库等。是运行Java编写的程序的必备环境。
    一句话解释:JDK用于开发,JRE用于运行,JDK包含JRE。

2. ==和equals的区别是什么?
基本引用类型(byte,short,char,int,long,float,double,boolean):==为值比较。
引用数据类型(class,interface,array):==为内存地址比较。
对于equals来说,equals其实是属于Object超类定义实现的,源代码如下:

// Object超类equals实现
public boolean equals(Object obj) {
    return (this == obj);
}

由源代码可得,实际上equals等同于==。
但是,对于String、Integer等包装类来说,它们实在对equals进行过重写,使得equals功能为值比较。源代码如下:

// String类型equals实现
public boolean equals(Object anObject) {
    // 如果传入的类型与本类型内存地址一致,则直接返回true
    if (this == anObject) {
        return true;
    }
    // 如果传入的类型也为String类型,那么进行字符串值比较
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}
// Integer类型equals实现
public boolean equals(Object obj) {
    // 如果传入的类型与本类型相同,则返回本类型的值与传入类型的值的对比
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

3.两个对象的hashCode()相同,则equals()也一定为true,对吗?
要解决这个问题,需要理解什么是hash?
维基百科解释为:散列函数(英语:Hash function)又称散列算法哈希函数,是一种从任何一种数据中创建小的数字“指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来。该函数将数据打乱混合,重新创建一个叫做散列值(hash values,hash codes,hash sums,或hashes)的指纹。散列值通常用一个短的随机字母和数字组成的字符串来代表。[1]好的散列函数在输入域中很少出现散列冲突。在散列表数据处理中,不抑制冲突来区别数据,会使得数据库记录更难找到。
因此可知,hash是可能存在散列冲突的:即不同的两个值,hash后的结果却是一致的。
hashCode为超类Object实现的方法,它是调用本地方法hashCode()实现的。源代码如下:

public native int hashCode();

因此hash冲突在Java的hashCode()实现中也是存在的,因此也存在多种hash冲突的解决方案,如开放地址法、拉链法等。
因此可得结论:hashCode()结果相同,equals的结果不一定为true。

4.final在Java中有什么作用?
在Java中,final可以用来修饰类、函数和变量。final类中的所有方法,会被隐式的指定为final方法。
当其修饰类时,表示该类不可继承。

public final class Person {
}

当其修饰方法时,表示该方法不可被重写。类的private方法会被隐式的指定为final方法。

public class Person {
    final void say() {
        System.out.println("say...");
    }
}

当其修饰变量时,如果该变量类型为基本数据类型,则表示该变量不可被修改;如果该变量为引用数据类型时,则表示该变量引用地址不可被修改。

final String A = "123";

5.Java中的Math.round(-1.5)等于多少?
在Java中,四舍五入的根本实现可以理解为:在原值的基础上+0.5,然后向下取整。源代码如下:

public static int round(float a) {
    int intBits = Float.floatToRawIntBits(a);
    int biasedExp = (intBits & FloatConsts.EXP_BIT_MASK)
            >> (FloatConsts.SIGNIFICAND_WIDTH - 1);
    int shift = (FloatConsts.SIGNIFICAND_WIDTH - 2
            + FloatConsts.EXP_BIAS) - biasedExp;
    if ((shift & -32) == 0) { // shift >= 0 && shift < 32
        // a is a finite number such that pow(2,-32) <= ulp(a) < 1
        int r = ((intBits & FloatConsts.SIGNIF_BIT_MASK)
                | (FloatConsts.SIGNIF_BIT_MASK + 1));
        if (intBits < 0) {
            r = -r;
        }
        // In the comments below each Java expression evaluates to the value
        // the corresponding mathematical expression:
        // (r) evaluates to a / ulp(a)
        // (r >> shift) evaluates to floor(a * 2)
        // ((r >> shift) + 1) evaluates to floor((a + 1/2) * 2)
        // (((r >> shift) + 1) >> 1) evaluates to floor(a + 1/2)
        return ((r >> shift) + 1) >> 1;
    } else {
        // a is either
        // - a finite number with abs(a) < exp(2,FloatConsts.SIGNIFICAND_WIDTH-32) < 1/2
        // - a finite number with ulp(a) >= 1 and hence a is a mathematical integer
        // - an infinity or NaN
        return (int) a;
    }
}

public static long round(double a) {
    long longBits = Double.doubleToRawLongBits(a);
    long biasedExp = (longBits & DoubleConsts.EXP_BIT_MASK)
            >> (DoubleConsts.SIGNIFICAND_WIDTH - 1);
    long shift = (DoubleConsts.SIGNIFICAND_WIDTH - 2
            + DoubleConsts.EXP_BIAS) - biasedExp;
    if ((shift & -64) == 0) { // shift >= 0 && shift < 64
        // a is a finite number such that pow(2,-64) <= ulp(a) < 1
        long r = ((longBits & DoubleConsts.SIGNIF_BIT_MASK)
                | (DoubleConsts.SIGNIF_BIT_MASK + 1));
        if (longBits < 0) {
            r = -r;
        }
        // In the comments below each Java expression evaluates to the value
        // the corresponding mathematical expression:
        // (r) evaluates to a / ulp(a)
        // (r >> shift) evaluates to floor(a * 2)
        // ((r >> shift) + 1) evaluates to floor((a + 1/2) * 2)
        // (((r >> shift) + 1) >> 1) evaluates to floor(a + 1/2)
        return ((r >> shift) + 1) >> 1;
    } else {
        // a is either
        // - a finite number with abs(a) < exp(2,DoubleConsts.SIGNIFICAND_WIDTH-64) < 1/2
        // - a finite number with ulp(a) >= 1 and hence a is a mathematical integer
        // - an infinity or NaN
        return (long) a;
    }
}

因此,-1.5四舍五入结果为(-1.5+0.5)向下取整为-1。

6.String属于基础的数据类型吗?
Java的数据类型分为基础数据类型和引用数据类型。
其中基础数据类型为8种:

  • 整形:byte、short、int、long
  • 浮点型:float、double
  • 字符型:char
  • 布尔型:boolen
    因此String不属于基础数据类型,而是引用数据类型。

7.Java中操作字符串都有哪些类型?它们之间有什么区别?
Java中操作字符串都有String、StringBuffer、StringBuilder。
String:使用final修饰,其返回返回都为new String。对String对象的任何更改都会生成新的String对象。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    ...
    public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; /* avoid getfield opcode */

            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                // 返回新的String对象
                return new String(buf, true);
            }
        }
        return this;
    }
    ...
}

StringBuffer:大部分方法都使用了synchronized修饰,为线程安全的类,推荐在多线程并发的情况下使用。

 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
    ...
    /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @since      1.5
     */
    @Override
    public synchronized StringBuffer append(CharSequence s, int start, int end)
    {
        toStringCache = null;
        super.append(s, start, end);
        return this;
    }
    ...
}

StringBuild:类似于StringBuffer,但是方法未使用synchornized进行修饰,为线程不安全的类,但是使用效率上要远高于StringBuffer。

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
    ...
    @Override
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
    ...
}

总结:Java中操作字符串的类型共有三种,分别为String、StringBuffer、StringBuilder。其中String为不可变的,适用于字符串生成不再变化的场景;StringBuffer为线程安全型,适用于需要大量拼接字符串且对线程安全要求较高的场景;StringBuilder为线程不安全类型,适用于需要大量拼接字符串且对线程安全要求较低的场景。

8.String str = "i"与String str = new String("i")一样吗?
java String str = "i",相当于将内存地址中的"i"的地址赋值给str变量。如果此时再次定义java String str2 = "i",那么str和str2的地址相同。

    public static void main(String[] args) {
        String str1 = "i";
        String str2 = "i";
        System.out.println(str1 == str2);
    }

java String str = new String("i"),实际上是重新创建了对象,并赋值为"i",虽然多次赋值的值相同,但是其内存地址并不相同。

      public static void main(String[] args) {
        String str1 = new String("i");
        String str2 = new String("i");
        System.out.println(str1.equals(str2));
        System.out.println(str1 == str2);
    }

9.如何将字符串反转?
如果此处考察的是Java基础,则可以使用StringBuffer或者StringBuilder进行反转。

    public static void main(String[] args) {
        String str = "abcdefg";
        String res = new StringBuilder(str).reverse().toString();
        System.out.println(res);
    }

StringBuilder反转实现源码:

    // StringBuilder源码,该方法继承自AbstractStringBuilder
    @Override
    public StringBuilder reverse() {
        super.reverse();
        return this;
    }

    // AbstractStringBuilder源码
    public AbstractStringBuilder reverse() {
        boolean hasSurrogates = false;
        int n = count - 1;
        for (int j = (n-1) >> 1; j >= 0; j--) {
            int k = n - j;
            char cj = value[j];
            char ck = value[k];
            value[j] = ck;
            value[k] = cj;
            if (Character.isSurrogate(cj) ||
                Character.isSurrogate(ck)) {
                hasSurrogates = true;
            }
        }
        if (hasSurrogates) {
            reverseAllValidSurrogatePairs();
        }
        return this;
    }

如果此处考察的是算法,则可以使用多种方法进行反转。例如:

    public static void main(String[] args) {
        String str = "abcdefg";
        char[] strArr = str.toCharArray();
        int i = 0;
        int j = strArr.length - 1;
        while (i < j) {
            char temp = strArr[i];
            strArr[i++] = strArr[j];
            strArr[j--] = temp;
        }
        System.out.println(new String(strArr));
    }

10.String类的常用方法有哪些?
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():字符串两端空白去除。
split():将字符串按照指定分隔符分割为字符串数组。
getBytes():返回字符串的byte类型的数据。
length():返回字符串的字符长度。
toLowerCase():将字符串转换为全部小写。
toUpperCase():将字符串转换为全部大写。
substring():截取字符串。
...

11.抽象类必须要有抽象方法吗?
抽象类中的方法不需要必须是抽象法。
但是拥有抽象方法的类必须是抽象类。

public abstract class Person {
    protected String name;
    protected int age;
    
    public abstract void say();
    
    public void play() {
        System.out.println("play...");
    }
}

12.普通类和抽象类有哪些区别?
抽象类和普通类是相对的概念。通常抽象类是由一系列普通类的共性抽象而成,例如:男人、女人的普通类,可以抽象成人类的类。

  • 抽象类必须使用abstract关键字修饰,而普通类不可以使用该关键字修饰。
  • 普通类可以实例化,抽象类不可以实例化。
  • 抽象类方法必须为public或者protected,而普通类还可以使用private(private修饰的方法不可以被继承)。
  • 一个普通类若继承自抽象类,则必须实现抽象类中的抽象方法必须。如果子类没有实现父抽象类中抽象方法,那么该子类必须也是抽象类。

13.抽象类能使用final修饰吗?
被final关键字修饰的类不可被继承,因此抽象类不能使用final关键字进行修饰。

14.接口和抽象类有什么区别?

  • 从概念上来说,抽象类是对事物本质的抽象,例如男人、女人和人类;而接口是对动作的抽象,例如说话、吃饭等。
  • 从设计层面来说,抽象类一种模板设计,而接口是一种行为规范。如果抽象类中新增了方法,子类是无需进行更新的;但是接口内新增了方法,所有实现该接口的类必须进行更新。
  • 从语法层面上来说
    • 抽象类可以提供成员方法的实现细节,而接口中只能存在java public abstract方法。
    • 抽象类中的成员变量可以是各种类型的,但是接口中的成员变量只能是java public static final类型的。
    • 抽象类中可以包含静态方法和静态代码块,而接口中不能含有静态方法和静态代码块。
    • 一个类只能继承一个抽象类,但是可以实现多个接口。

15.Java中的IO流分为几种?

  • 按照流的流向分:可以分为输入流和输出流。
  • 按照流的划分单元分:可以分为字节流和字符流。
    • 字节流处理的最基本单位1byte,通常用来处理二进制数据。
    • 字符流处理的最基本单位为2byte的Unicode,通常用来处理文本数据。
  • 按照流的角色划分为节点流和处理流。
    Java IO.png
    图片来源于:https://blog.csdn.net/qq_35771266/article/details/94850047

16.BIO、NIO、AIO有什么区别?

  • BIO(Blocking IO),同步阻塞IO。
  • NIO(Non-Blocking IO),同步非阻塞IO。
  • AIO(Aysnc IO),异步非阻塞IO。

17.Files的常用方法有哪些?
Files.exists():检测文件路径是否存在。
Files.createFile():创建文件。
Files.createDirectory():创建目录。
Files.delete():删除文件或者目录。
Files.copy():复制文件。
Files.move():移动文件。
Files.size():查看文件数量。
Files.read():读取文件。
Files.write():写入文件。
...

相关文章

  • 1.Java基础

    1.常量\变量 常量:关键字为 final 变量:关键字为 数据类型 2.输入\输出 输入:使用强大的Scanne...

  • 1.java基础

    java具有跨平台性,既能在win使用也能在Linux.mac使用,一次编译可以到处运行。因为java在win、m...

  • 1.Java基础

    题目来源于:https://www.bilibili.com/read/cv7046891 1.JDK和JRE有什...

  • Java基础知识整理(一)

    1.Java基础知识体系 2.Java技术体系平台 3.Java语言特点与核心机制 1.Java基础知识体系 2....

  • 1.java入门基础

    java是一门相对简单的语言,语法非常简单,复杂的都被屏蔽了,而且有非常好用的IDE来辅助开发。本章讲解主要涉及j...

  • 面试题汇总

    1.Java基础面试问题 Java基础之基础问题 Java基础之面向对象 Java基础之数据结构 Java基础之I...

  • Java学习路线

    1.Java基础学习(李兴华) https://edu.aliyun.com/course/34 零基础入门 ht...

  • JAVA基础知识

    JAVA基础知识 一. 开发工具的选择: 1.java: E...

  • java基础,每天都应该复习

    java基础,每天都应该复习 1.Java语言基础(选择结构switch语句的格式及其解释)(掌握) A:swit...

  • 在Alibaba广受喜爱的“Java突击宝典”简直太牛了

    0-1年:夯实基础 1.Java基础(Java异常分类及处理+Java反射+Java注解+Java内部类+Java...

网友评论

      本文标题:1.Java基础

      本文链接:https://www.haomeiwen.com/subject/asbhyktx.html