Java基础面试题

参考

https://snailclimb.gitee.io/javaguide/#/docs/java/basis/Java%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86

https://thinkwon.blog.csdn.net/article/details/104390612

1.面向对象和面向过程的区别?

面向过程

优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素。

缺点:没有面向对象易维护、易复用、易扩展

面向对象

优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护

缺点:性能比面向过程低

面向对象的编程方式使得每一个类都只做一件事。而面向过程会让一个类越来越全能,就像一个管家一样做了所有的事

面向对象的方式比较容易维护,它趋近于抽象出事物的共同属性和行为封装成一个类去实现,而面向过程怎么快速实现一个功能。可以参考活字印刷和普通印刷!

2.JAVA语言有哪些特点?

Java语言共有十大特点,分别为:简单性、面向对象、分布性、编译和解释性、稳健性、安全性、可移植性、高性能、多线索性、动态性。

1、简单性:Java语言继承了C++语言的优点,去掉了C++中学习起来比较难的多继承、指针等概念,所以Java语言学习起来更简单,使用起来也更方便。

2、面向对象:Java是一种面向对象的编程语言。

3、分布性:Java设计成支持在网络上应用,它是分布式语言。所以只要用Java编写了一个程序,就可以到处应用。可以节省大量人力物力。

4、编译和解释性:Java编译程序生成字节码,而不是通常的机器码,这使得Java开发程序比用其他语言开发程序快很多。

5、稳健性:Java刚开始被设计出来就是为了写高可靠和稳健的软件的。所以用Java写可靠的软件很容易。目前许多第三方交易系统、银行平台的前台和后台电子交易系统等都会用Java语言开发。

6、安全性:Java的存储分配模型是它防御恶意代码的主要方法之一。所以很多大型企业级项目开发都会选择用Java开发。

7、可移植性:Java并不依赖平台,用Java编写的程序可以运用到任何操作系统上。

8、高性能:Java是一种先编译后解释的语言,所以它不如全编译性语言快。但Java设计者制作了“及时”编译程序,这样就可以实现全编译了。

9、多线索性:Java是多线索语言,它可以同时执行多个程序,能处理不同任务。

10、动态性:Java语言设计成适应于变化的环境,它是一个动态的语言。

java是一个跨平台的语言,他有着一处编译,四处运行的特点。基于java语言编译运行的机制,.java首先被javac编译为.class文件,在基于不同操作系统的jvm上,jvm将.class文件解析成cpu能够识别的指令,从而完成跨平台的特性。java也是一个面向对象的语言,它有着封装、继承、多态的特性。封装就是对外隐藏类的属性以及方法细节信息,保证类的安全。比如一个person类,我们是不应该能任意修改其中类的age,name属性的,如果是public修饰符,我们就可以任意修改age,name属性,这会造成程序的混乱,所以封装性是非常有必要的。但是封装性并不是绝对安全,利用java的反射可以破坏封装性,从而能修改对应的属性值。继承也是面向对象的一大特性,java支持多层继承,不支持多重继承,但是java的接口可以多重继承。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。通过继承的特性,Java可以提供代码的复用性,子类可以无需重写就调用父类的方法,如果子类有一些新的实现方式,它可以选择重写父类方法,这就是重写。说到了重写,那么这就说到了java的另一个特性,多态!多态表示一个对象具有多种的状态。具体表现为父类的引用指向子类的实例。多态的表现形式有两种,一种是运行时的多态,就是刚刚说的重写。另一种时编译时的多态,就是重载!重写和重载有什么区别呢,重写的方法方法名,返回类型参数必须和父类一致,但是方法的修饰符子类必须大于等于父类,子类的异常必须小于等于父类。重载要求同名方法的参数列表不同(参数类型,参数个数甚至是参数顺序)。重载的时候,返回值类型可以相同也可以不相同,但是无法以返回型别作为重载函数的区分标准。多态的弊端是不能使用子类特有的成员属性和子类特有的成员方法

向上转型:Super super=new Zi();

向下转型:Zi zi=(Zi)super;

3.重写和重载有什么区别?

方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。

重载(Overload):发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不同、顺序不同),与方法返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分

重写(Override):发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类;如果父类方法访问修饰符为private则子类中就不是重写

区别点重载方法重写方法
发生范围一个类中子类
参数列表必须修改一定不可以修改
返回类型可修改(但是不可以用返回类型做重载的判断条件)子类方法返回值类型应比父类方法返回值类型更小或相等
异常可修改子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等
返回修饰符可修改一定不能做更严格的限制(可以降低限制)
发生阶段编译期运行期

 

4.面向对象的三大特征?

封装:封装就是对外隐藏类的属性以及方法细节信息,保证类的安全。比如一个person类,我们是不应该能任意修改其中类的age,name属性的,如果是public修饰符,我们就可以任意修改age,name属性,这会造成程序的混乱,所以封装性是非常有必要的。但是封装性并不是绝对安全,利用java的反射可以破坏封装性,从而能修改对应的属性值。

继承:继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码。

关于继承如下 3 点请记住:

  1. 子类拥有父类非 private 的属性和方法。

  2. 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。

  3. 子类可以用自己的方式实现父类的方法。

继承是为了多态

多态:事物在运行过程中存在不同的状态

多态的存在有三个前提:
1.要有继承关系
2.子类要重写父类的方法
3.父类引用指向子类对象

向上转型:Super super=new Zi();

向下转型:Zi zi=(Zi)super;

多态的弊端,就是:不能使用子类特有的成员属性和子类特有的成员方法

解决方式:将向上转型的对象进行向下转型即可

多态的实现方式有两种,分别是重载和重写。

多态参考https://www.zhihu.com/question/30082151/answer/120520568

除了封装、继承、多态之外,还有一个特性是抽象

抽象:抽线就是对同一个事的共有的属性(特征)和方法(功能/行为)进行抽取、归纳、总结。如:汽车都有轮子、发动机等这些就是汽车的属性,汽车能跑、能载人载物等这些就是汽车的功能。这样就可以把汽车的这些功能与属性抽取出来写在一个类中,供汽车这一类事物使用。

5.JDK 、JRE、JVM 有什么区别?

JDK是Java Devlopment Kit的缩写,它是功能齐全的Java SDK。它拥有JRE所拥有的一切,还有编译器(javac)和工具(如javadoc和jdb-->JAVA调试器)。它能够创建和编译程序。

JRE是 Java 运行时环境。它是运行已编译 Java 程序所需的所有内容的集合,包括 Java 虚拟机(JVM),Java 类库,java 命令和其他的一些基础构件。但是,它不能用于创建新程序。

如果你只是为了运行一下 Java 程序的话,那么你只需要安装 JRE 就可以了。如果你需要进行一些 Java 编程方面的工作,那么你就需要安装 JDK 了。但是,这不是绝对的。有时,即使您不打算在计算机上进行任何 Java 开发,仍然需要安装 JDK。例如,如果要使用 JSP 部署 Web 应用程序,那么从技术上讲,您只是在应用程序服务器中运行 Java 程序。那你为什么需要 JDK 呢?因为应用程序服务器会将 JSP 转换为 Java servlet,并且需要使用 JDK 来编译 servlet。

Java 虚拟机(JVM)是运行 Java 字节码的虚拟机。JVM 有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。字节码和不同系统的 JVM 实现是 Java 语言“一次编译,随处可以运行”的关键所在。

6.字符型常量和字符串常量的区别?

形式上: 字符常量是单引号引起的一个字符; 字符串常量是双引号引起的 0 个或若干个字符

含义上: 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)

占内存大小: 字符常量只占 2 个字节; 字符串常量占若干个字节 (注意: char 在 Java 中占两个字节)

字符封装类 Character 有一个成员常量 Character.SIZE 值为 16,单位是bits,该值除以 8(1byte=8bits)后就可以得到 2 个字节

7.continue、break、和 return 的区别是什么?

在循环结构中,当循环条件不满足或者循环次数达到要求时,循环会正常结束。但是,有时候可能需要在循环的过程中,当发生了某种条件之后 ,提前终止循环,这就需要用到下面几个关键词:

continue :指跳出当前的这一次循环,继续下一次循环。

break :指跳出整个循环体,继续执行循环下面的语句。

return 用于跳出所在方法,结束该方法的运行。return 一般有两种用法:

return; :直接使用 return 结束方法执行,用于没有返回值函数的方法

return value; :return 一个特定值,用于有返回值函数的方法

8.== 和 equals 的区别是什么?

==比较的是对象的内存地址,就是判断两个对象的地址是不是相等(基本数据类型==比较的是值,引用数据类型比较的 是内存地址)。

equals():它的作用也是判断两个对象是否相等,它不能用于比较基本数据类型的变量。equals()方法存在于object类中,而object类是所有类的直接或间接父类。

public boolean equals(Object obj) {

return (this == obj);

}

如果类没有覆盖equals()方法,那它就和==是一样的,可以从底层源码得出。如果类覆盖了equals()方法,那么我们将比较对象的内容是否相等,比较典型的就是String类。

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    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;
}

public class Main {
    public static void main(String[] args) {
        //-128 ~ +127 之间
        Integer a = 5;
        int b = 5;
        Integer c = new Integer(5);
        Integer d = 5;
        //true
        System.out.println(a.equals(b));
        //true,a是包装类,b是普通类型,所以a会自动拆箱为
        //普通类型,两个普通类型的值用==比较       
        System.out.println(a == b);
        //true
        System.out.println(a.equals(c));
        //a和c是两个对象,所以是false
        System.out.println(a == c);
        //true,因为都是包装类,在-128到127之间有缓存,所以是同一个对象
        System.out.println(a == d);
        System.out.println("===============");
        //-128 ~ +127 之外
        a = 128;
        b = 128;
        c = new Integer(128);
        d = 128;
        //true
        System.out.println(a.equals(b));
        //true,a是包装类,b是普通类型,所以a会自动拆箱为普通类型,同于a.equals(b),y
        System.out.println(a == b);
        //true
        System.out.println(a.equals(c));
        //false,不同对象
        System.out.println(a == c);
        //false,不同对象
        System.out.println(a == d);
    }
}

9.两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?

hashCode():hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在 JDK 的 Object 类中,这就意味着 Java 中的任何类都包含有 hashCode() 函数。另外需要注意的是: Object 的 hashcode 方法是本地方法,也就是用 c 语言或 c++ 实现的,该方法通常用来将对象的 内存地址 转换为整数之后返回。

当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的 hashcode,HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals() 方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。

如果两个对象相等,则 hashcode 一定也是相同的。两个对象相等,对两个对象分别调用 equals 方法都返回 true。但是,两个对象有相同的 hashcode 值,它们也不一定是相等的 。因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖。equals()相等的的两个等价对象因为hashCode不同,所以在hashmap中的table数组的下标不同,从而这两个对象就会同时存在于集合中,在调用hashmap集合中的方法时就会出现逻辑的错误,也就是,你的equals()方法也“白白”重写了。

因为 hashCode() 所使用的杂凑算法也许刚好会让多个对象传回相同的杂凑值。越糟糕的杂凑算法越容易碰撞,但这也与数据值域分布的特性有关(所谓碰撞也就是指的是不同的对象得到相同的 hashCode。

我们刚刚也提到了 HashSet,如果 HashSet 在对比的时候,同样的 hashcode 有多个对象,它会使用 equals() 来判断是否真的相同。也就是说 hashcode 只是用来缩小查找成本。

10.final 在 java 中有什么作用?

final关键字,意思是最终的、不可修改的,最见不得变化 ,用来修饰类、方法和变量,具有以下特点:

final修饰的类不能被继承,final类中的所有成员方法都会被隐式的指定为final方法;

final修饰的方法不能被重写;

final修饰的变量是常量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能让其指向另一个对象。

说明:使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的Java版本已经不需要使用final方法进行这些优化了)。类中所有的private方法都隐式地指定为final。

在java编程思想第四版中有提到Vector这个类大量使用final导致无法对其进行修改,所以它目前的使用场景太少了。

11.java 中的 Math.round(-1.5) 等于多少?

public static void main(String[] args) {
    //取值为最接近的long类型数,如果两边一样以大的为准
    System.out.println(Math.round(-0.5));//0
    System.out.println(Math.round(-0.4));//0
    System.out.println(Math.round(-1.5));//-1
    System.out.println(Math.round(-2.5));//-2
    System.out.println(Math.round(-2.6));//-3
    System.out.println(Math.round(2.5));//3
    System.out.println(Math.round(2.1));//2
    System.out.println(Math.round(0.5));//1
    System.out.println(Math.round(0.4));//0
}

12.String 属于基础的数据类型吗?

String不是基本的数据类型,是final修饰的java类,java中的基本类型一共有8个,它们分别为:

1 字符类型:byte,char

2 基本整型:short,int,long

3 浮点型:float,double

4 布尔类型:boolean

整数类型

int 4字节(32位) -231~ 231-1 0 Integer

short 2字节(16位) -215~215-1 0 Short

long 8字节(64位) -263~263-1 0 Long

byte 1字节(8位) -27~27-1 0 Byte

浮点类型

float 4字节(32位) -3.4e+38 ~ 3.4e+38 0.0f Float

double 8字节(64位) -1.7e+308 ~ 1.7e+308 0 Double

字符型

char 2字节(16位) u0000~uFFFF('\u0000' ) ‘0’ Character

(0~216-1(65535))  

布尔型

boolean 1/8字节(1位) true, false FALSE Boolean

13.java 中操作字符串都有哪些类?它们之间有什么区别?

String : final修饰,String类的方法都是返回new String。即对String对象的任何改变都不影响到原对象,对字符串的修改操作都会生成新的对象。

StringBuffer : 对字符串的操作的方法都加了synchronized,保证线程安全。

StringBuilder : 不保证线程安全,在方法体内需要进行字符串的修改操作,可以new StringBuilder对象,调用StringBuilder对象的append、replace、delete等方法修改字符串。

java中操作字符串的类,我知道的有三个类,分别是String,StringBuffer和StringBuilder.这三个类都是以char[]的形式保存的字符串,但是String类型的字符串是不可变的,对String类型的字符床做修改操作都是相当于重新创建对象.而对StringBuffer和StringBuilder进行增删操作都是对同一个对象做操作.StringBuffer中的方法大部分都使用synchronized关键字修饰,所以StringBuffer是线程安全的,StringBuilder中的方法则没有,线程不安全,但是StringBuilder因为没有使用使用synchronized关键字修饰,所以性能更高,在单线程环境下我会选择使用StringBuilder,多线程环境下使用StringBuffer.如果声明的这个字符串几乎不做修改操作,那么我就直接使用String,因为不调用new关键字声明String类型的变量的话它不会在堆内存中创建对象,直接指向String的常量池,并且可以复用.效率更高.

14.String str="i"与 String str=new String("i")一样吗?

String str="i";

这句话的意思是把“i”这个值在内存中的地址赋给str,如果再有String str3="i";那么这句话的操作也是把“i”这个值在内存中的地址赋给str3,这两个引用的是同一个地址值,他们两个共享同一个内存。

而String str2 = new String("i");

则是将new String("i");的对象地址赋给str2,需要注意的是这句话是新创建了一个对象。如果再有String str4= new String("i");那么相当于又创建了一个新的对象,然后将对象的地址值赋给str4,虽然str2的值和str4的值是相同的,但是他们依然不是同一个对象了。

需要注意的是:String str="i"; 因为String 是final类型的,所以“i”应该是在常量池。

而new String("i");则是新建对象放到堆内存中。

参考https://zhuanlan.zhihu.com/p/60643031

15.如何将字符串反转?

        //利用StringBuilder(str).reverse()
        String s = "hello";
        StringBuilder stringBuilder = new StringBuilder(s).reverse();
        System.out.println(stringBuilder.toString());
        //利用数组倒序
        char[] charArray = s.toCharArray();
        char[] newArray = new char[charArray.length];
        for (int i = 0; i < charArray.length; i++) {
            newArray[i] = charArray[charArray.length - i - 1];
        }
        System.out.println(String.valueOf(newArray));
        //利用栈数据结构
        char[] str = s.toCharArray();
        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < str.length; i++) {
            stack.push(str[i]);
        }
        StringBuilder stringBuilder1 = new StringBuilder();
        for (int i = 0; i < str.length; i++) {
            stringBuilder1.append(stack.pop());
        }
        System.out.println(stringBuilder1.toString());

https://www.jianshu.com/p/8d6c3d69d87f

https://baijiahao.baidu.com/s?id=1672154047514774648&wfr=spider&for=pc

16.String 类的常用方法都有那些?

(1).indexOf():返回指定字符的索引。

(2).charAt():返回指定索引处的字符。

(3).replace():字符串替换。

(4).trim():去除字符串两端空白。

(5).split():分割字符串,返回一个分割后的字符串数组。

(6).getBytes():返回字符串的 byte 类型数组。

(7).length():返回字符串长度。

(8).toLowerCase():将字符串转成小写字母。

(9).toUpperCase():将字符串转成大写字符。

(10).substring():截取字符串。

(11).equals():字符串比较。

17.普通类和抽象类有哪些区别?

  • 抽象类不能被直接实例化

  • 抽象类可以有抽象方法,抽象方法只需申明,无需实现

  • 含有抽象方法的类必须申明为抽象类

  • 抽象类的子类必须实现抽象类中所有抽象方法,否则这个子类也是抽象类

  • 抽象方法不能被声明为静态

  • 抽象方法不能用 private 修饰

  • 抽象方法不能用 final修饰

18.抽象类能使用 final 修饰吗?

抽象类不能同时又是final,因为final修饰的类是不能被继承的,而抽象类如果想要被实例化必须要有子类去继承它,这样就前后矛盾,编译器将会提示错误。

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

接口的方法默认是 public,所有方法在接口中不能有实现(Java 8 开始接口方法可以有默认实现),而抽象类可以有非抽象的方法。

接口中除了 static、final 变量,不能有其他变量,而抽象类中则不一定。

一个类可以实现多个接口,但只能实现一个抽象类。接口自己本身可以通过 extends 关键字扩展多个接口。

接口方法默认修饰符是 public,抽象方法可以有 public、protected 和 default 这些修饰符(抽象方法就是为了被重写所以不能使用 private 关键字修饰!)。

从设计层面来说,抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为的规范。

1、抽象类可以有构造,只不过不能new。

2、接口中可以有变量,但是无论你怎么写,最后都是public static final的。

3、抽象类中可以有静态方法,接口中也可以有。

扩展:

1、接口中可以有非抽象的方法,比如default方法(Java 1.8)。

2、接口中可以有带方法体的方法。(Java 1.8)

3、接口中的方法默认是public的。

参数抽象类接口
声明抽象类使用abstract关键字声明接口使用interface关键字声明
实现子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现子类使用implements关键字来实现接口。它需要提供接口中所有声明的方法的实现
构造器抽象类可以有构造器接口不能有构造器
访问修饰符抽象类中的方法可以是任意访问修饰符接口方法默认修饰符是public。并且不允许定义为 private 或者 protected
多继承一个类最多只能继承一个抽象类一个类可以实现多个接口
字段声明抽象类的字段声明可以是任意的接口的字段默认都是 static 和 final 的

参考https://www.zhihu.com/question/20149818

20.抽象类必须要有抽象方法吗?

1.如果一个类使用了abstract关键字修饰,那么这个类就是一个抽象类,抽象类只能作为其他类的父类

2.抽象类允许包含抽象成员,但是这不是必须的,抽象类可以没有抽象方法,也可以有非抽象方法。

3.一个类如果包含抽象方法,那么这个类必须是抽象类,否则编译就会报错。

4.最关键的一点就是如果一个类是抽象类,那么这个类是不能被实例化的。抽象类如果含有抽象的变量或者值,则他们要么是null,要么包含了对非抽象类的实例的引用。

21.java 中 IO 流分为几种?

  • 按照流的流向分,可以分为输入流和输出流;
  • 按照操作单元划分,可以划分为字节流和字符流;
  • 按照流的角色划分为节点流和处理流。

Java Io 流共涉及 40 多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java I0 流的 40 多个类都是从如下 4 个抽象类基类中派生出来的。

  • InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。

  • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

字符流是由 Java 虚拟机将字节转换得到的,问题就出在这个过程还算是非常耗时,并且,如果我们不知道编码类型就很容易出现乱码问题。所以, I/O 流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。因为字符流有缓冲区的存在,所以效率会高一些!

参考https://blog.csdn.net/qq_27093465/article/details/52472506

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

简答

  • BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
  • NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
  • AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。

详细回答

  • BIO (Blocking I/O): 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
  • NIO (New I/O): NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发
  • AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。

23.Files的常用方法都有哪些?

Files. exists():检测文件路径是否存在。

Files. createFile():创建文件。

Files. createDirectory():创建文件夹。

Files. delete():删除一个文件或目录。

Files. copy():复制文件。

Files. move():移动文件。

Files. size():查看文件个数。

Files. read():读取文件。

Files. write():写入文件。

24.基本类型和包装类型的区别

1.包装类型可以为 null,而基本类型不可以

数据库的查询结果可能是 null,如果使用基本类型的话,因为要自动拆箱(将包装类型转为基本类型,比如说把 Integer 对象转换成 int 值),就会抛出NullPointerException的异常

2.包装类可以用于基本泛型,而基本类型不可以

为什么呢?因为泛型在编译时会进行类型擦除,最后只保留原始类型,而原始类型只能是 Object 类及其子类——基本类型是个特例。

3.基本类型比包装类更高效

基本类型在栈中直接存储的具体数值,而包装类型则存储的是堆中的引用,相比较于基本类型而言,包装类型需要占用更多的内存空间。假如没有基本类型的话,对于数值这类经常使用到的数据来说,每次都要通过 new 一个包装类型就显得非常笨重。所以包装类无法通过==判断值是否相同

4.两个包装类型的值可以相同,但却不相等

将“==”操作符应用于包装类型比较的时候,其结果很可能会和预期的不符

public class Main {
    public static void main(String[] args) {
        Integer a = new Integer(1);
        Integer b = new Integer(1);
        //true
        System.out.println(a == b);
        //true
        System.out.println(a.equals(b));
    }
}

5.自动拆箱和自动装箱

把基本类型转换成包装类型的过程叫做装箱。

反之,把包装类型转换成基本类型的过程叫做拆箱

装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)。

public class Main {
    public static void main(String[] args) {
        // 1)基本类型和包装类型
        int a = 100;
        Integer b = 100;
        //true,因为基本类型和包装类型进行 == 比较,
        // 这时候 b 会自动拆箱,直接和 a 比较值,所以结果为 true
        System.out.println(a == b);

        // 2)两个包装类型
        Integer c = 100;
        Integer d = 100;
        //true,当需要进行自动装箱时,如果数字在 -128 至 127 之间时,
        // 会直接使用缓存中的对象,而不是重新创建一个对象
        System.out.println(c == d);

        // 3)
        c = 200;
        d = 200;
        //false,当需要进行自动装箱时,如果数字在 -128 至 127 之间时,
        // 会直接使用缓存中的对象,而不是重新创建一个对象,200不在这个范围内
        System.out.println(c == d);
    }
}

参考https://zhuanlan.zhihu.com/p/84639233

25.Integer i = new Integer(xxx)和Integer i =xxx的区别?

  • 第一种方式不会触发自动装箱的过程;而第二种方式会触发;
  • 在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。

java在编译Integer i = 100 ;时,会翻译成为Integer i = Integer.valueOf(100)

基本类型在栈中直接存储的具体数值,而包装类型则存储的是堆中的引用,相比较于基本类型而言,包装类型需要占用更多的内存空间

java对于-128到127之间的数,会进行缓存,Integer i = 127时,会将127进行缓存,下次再写Integer j = 127时,就会直接从缓存中取,就不会new了

参考https://blog.csdn.net/xxqi1229/article/details/6871152

26.Java泛型了解么?什么是类型擦除?介绍一下常用的通配符?

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

Java 的泛型是伪泛型,这是因为 Java 在编译期间,所有的泛型信息都会被擦掉,这也就是通常所说类型擦除.

泛型一般有三种使用方式:泛型类、泛型接口、泛型方法。

//泛型类
public class Test <T>{
    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }

    @Override
    public String toString() {
        return "Test{" +
                "t=" + t +
                '}';
    }

    public static void main(String[] args) {
        Test<String> test=new Test<>();
        test.setT("hello");
        System.out.println(test);
        Test<Integer> test2=new Test<>();
        test2.setT(1);
        System.out.println(test2);
    }
}
//泛型接口
public interface Generator<T> {
    public T hello(T t);
}
//实现泛型接口,不指定类型
public class Impl01<T> implements Generator<T>{
    @Override
    public T hello(T t) {
        return t;
    }

    public static void main(String[] args) {
        Generator<String> impl01=new Impl01();
        System.out.println(impl01.hello("hello"));
        Generator<Integer> impl02=new Impl01();
        System.out.println(impl02.hello(1));
    }
}
//实现泛型接口,指定类型
public class Impl02 implements Generator<String> {
    @Override
    public String hello(String s) {
        return s;
    }

    public static void main(String[] args) {
        Generator impl01 = new Impl02();
        System.out.println(impl01.hello("hello"));
    }
}
//泛型方法
public class Test {
    public static <E> void printArray(E[] inputArray) {
        for (E element : inputArray) {
            System.out.printf("%s ", element);
        }
        System.out.println();
    }

    public static void main(String[] args) {
        // 创建不同类型数组: Integer, Double 和 Character
        Integer[] intArray = {1, 2, 3};
        String[] stringArray = {"Hello", "World"};
        printArray(intArray);
        printArray(stringArray);

    }
}

 

参考https://juejin.cn/post/6844903917835419661

27.什么是反射?

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

  • 优点: 运行期类型的判断,动态加载类,提高代码灵活度。

  • 缺点: 1,性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的 java 代码要慢很多。2,安全问题,让我们可以动态操作改变类的属性同时也增加了类的安全隐患。

在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架也大量使用到了反射机制。

举例:

1.我们在使用 JDBC 连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;

Spring 框架的 IOC(动态加载管理 Bean)创建对象以及 AOP(动态代理)功能都和反射有联系;

动态配置实例的属性;

获取Class对象的四种方式:

        //1.知道具体类
        Class test01=Test.class;
        System.out.println(test01);
        //2.通过 Class.forName()传入类的路径
        Class test02=Class.forName("com.kebo.test.Test");
        System.out.println(test02);
        //3.通过对象实例instance.getClass()
        Test test=new Test();
        System.out.println(test.getClass());
        //4.通过类加载器xxxClassLoader.loadClass()传入类路径获取
        ClassLoader classLoader = Test.class.getClassLoader();
        Class clazz4 = classLoader.loadClass("com.kebo.test.Test");
        System.out.println(clazz4);

28.什么是Java程序的主类?应用程序和小程序的主类有何不同?

一个程序中可以有多个类,但只能有一个类是主类。在Java应用程序中,这个主类是指包含main()方法的类。而在Java小程序中,这个主类是一个继承自系统类JApplet或Applet的子类。应用程序的主类不一定要求是public类,但小程序的主类要求必须是public类。主类是Java程序执行的入口点。

29.Java应用程序与小程序之间有那些差别?

简单说应用程序是从主线程启动(也就是main()方法)。applet小程序没有main方法,主要是嵌在浏览器页面上运行(调用init()线程或者run()来启动),嵌入浏览器这点跟flash的小游戏类似。

30.java和C++的区别

  • 都是面向对象的语言,都支持封装、继承和多态
  • Java不提供指针来直接访问内存,程序内存更加安全
  • Java的类是单继承的,C++支持多重继承;虽然Java的类不可以多继承,但是接口可以多继承。
  • Java有自动内存管理机制,不需要程序员手动释放无用内存

31.Oracle JDK 和 OpenJDK 的对比

  • Oracle JDK版本将每三年发布一次,而OpenJDK版本每三个月发布一次;

  • OpenJDK 是一个参考模型并且是完全开源的,而Oracle JDK是OpenJDK的一个实现,并不是完全开源的;

  • Oracle JDK 比 OpenJDK 更稳定。OpenJDK和Oracle JDK的代码几乎相同,但Oracle JDK有更多的类和一些错误修复。因此,如果您想开发企业/商业软件,我建议您选择Oracle JDK,因为它经过了彻底的测试和稳定。某些情况下,有些人提到在使用OpenJDK 可能会遇到了许多应用程序崩溃的问题,但是,只需切换到Oracle JDK就可以解决问题;

  • 在响应性和JVM性能方面,Oracle JDK与OpenJDK相比提供了更好的性能;

  • Oracle JDK不会为即将发布的版本提供长期支持,用户每次都必须通过更新到最新版本获得支持来获取最新版本;

  • Oracle JDK根据二进制代码许可协议获得许可,而OpenJDK根据GPL v2许可获得许可。

32.switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上

在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。从 Java5 开始,Java 中引入了枚举类型,expr 也可以是 enum 类型,从 Java 7 开始,expr 还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的

33.short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗

对于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 类型,因此 s1+1 运算结果也是 int型,需要强制转换类型才能赋值给 short 型。

而 short s1 = 1; s1 += 1;可以正确编译,因为 s1+= 1;相当于 s1 = (short(s1 + 1);其中有隐含的强制类型转换。

34.访问修饰符 public,private,protected,以及不写(默认)时的区别

定义:Java中,可以使用访问修饰符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。

分类

private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
default (即缺省,什么也不写,不使用任何关键字): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
public : 对所有类可见。使用对象:类、接口、变量、方法

访问修饰符图

35.final finally finalize区别

  • final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表
    示该变量是一个常量不能被重新赋值。
  • finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块
    中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
  • finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调
    用,当我们调用System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,一个对象是否可回收的
    最后判断。

参考https://www.cnblogs.com/wisefulman/p/10584515.html

https://zhuanlan.zhihu.com/p/339666218

36.this与super的区别

  • super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
  • this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
  • super()和this()类似,区别是,super()在子类中调用父类的构造方法,this()在本类内调用本类的其它构造方法。
  • super()和this()均需放在构造方法内第一行。
  • 尽管可以用this调用一个构造器,但却不能调用两个。
  • this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
  • this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
  • 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。

37.什么是 java 序列化?什么情况下需要序列化?

序列化:将 Java 对象转换成字节流的过程。

反序列化:将字节流转换成 Java 对象的过程。

当 Java 对象需要在网络上传输 或者 持久化存储到文件中时,就需要对 Java 对象进行序列化处理。

序列化的实现:类实现 Serializable 接口,这个接口没有需要实现的方法。实现 Serializable 接口是为了告诉 jvm 这个类的对象可以被序列化。

注意事项:

1.某个类可以被序列化,则其子类也可以被序列化

2.声明为 static 和 transient 的成员变量,不能被序列化。static 成员变量是描述类级别的属性,transient 表示临时数据

3.反序列化读取序列化对象的顺序要保持一致

我们知道,不同进程/程序间进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等,而这些数据都会以二进制序列的形式在网络上传送。

    那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?当然是可以的!如何做到呢?这就需要使用Java序列化与反序列化了。发送方需要把这个Java对象转换为字节序列,然后在网络上传输,接收方则需要将字节序列中恢复出Java对象。

将需要被序列化的类实现Serializable接口,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流

38.为什么要使用克隆?

想对一个对象进行处理,又想保留原有的数据进行接下来的操作,就需要克隆了。

克隆分浅克隆和深克隆,浅克隆后的对象中非基本对象和原对象指向同一块内存,因此对这些非基本对象的修改会同时更改克隆前后的对象。深克隆可以实现完全的克隆,可以用反射的方式或序列化的方式实现。

39.如何实现对象克隆?

1.实现 Cloneable 接口并重写 Object 类中的 clone() 方法;

2.实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

//浅克隆
class Person implements Cloneable {
    private int pid;
    private String name;
    public Person(int pid, String name) {
        this.pid = pid;
        this.name = name;
        System.out.println("Person constructor call");
    }
    public int getPid() {
        return pid;
    }
    public void setPid(int pid) {
        this.pid = pid;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    @Override
    public String toString() {
        return "Person [pid:"+pid+", name:"+name+"]";
    }
    public static void main(String[] args) throws CloneNotSupportedException {
        Person p1 = new Person(1, "test");//创建对象 Person p1
        Person p2 = (Person)p1.clone();//克隆对象 p1
        System.out.println(p1==p2);
        p2.setName("kb");//修改 p2的name属性,p1的name未变
        System.out.println(p1);
        System.out.println(p2);
    }
}

参考https://zhuanlan.zhihu.com/p/95686213

40.深拷贝和浅拷贝区别是什么?

浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。

深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。

浅拷贝的时候如果是基本数据类型,那么原对象变化不会引起拷贝对象的变化。如果是引用数据类型,那么会引起拷贝对象的变化,但是引用数据类型也实现了cloneable接口的话,它也不会引起拷贝对象的变化。String类型是一个比较特殊的类型,浅拷贝的时候改变String类型也无法改变拷贝对象,因为String类型的常量池的存在,如果String字符串发生了改变,那么它的地址必定发生改变,而被拷贝对象的地址仍然指向了原地址,所以它不会发生改变。

举例:Person类的age和name属性不会因为原对象改变而引起拷贝对象的改变。但如果Person类中有一个Address的引用数据类型,原对象中Address的id发生改变,那么拷贝对象也会发生改变。如果Address实现了cloneable接口,同样不会因为原对象改变而引起拷贝对象的改变。

我们都知道clone分为深clone和浅clone,基本类型能自动实现深clone,属于值传递,改变一个对象的值,另一个不会受影响。对于浅clone来讲,引用类型是传递引用,指向同一片内存空间,改变一个对象的引用类型的值,另一个对象也会随之改变。但是String类型却是一个特殊,String虽然属于引用类型,但是String类是不可改变的,它是一个常量,一个对象调用clone方法,克隆出一个新对象,这时候两个对象的同一个String类型的属性是指向同一片内存空间的,但是如果改变了其中一个,会产生一片新的内存空间,此时该对象的这个属性的引用将指向这片新的内存空间,此时两个对象的String类型的属性指向的就是不同的2片内存空间,改变一个不会影响到另一个,可以当做基本类型来使用。

41.throw 和 throws 的区别?

Throw

  1. 作用在方法内,表示抛出具体异常,由方法体内的语句处理。
  2. 具体向外抛出的动作,所以它抛出的是一个异常实体类。若执行了Throw一定是抛出了某种异常。

Throws

  1. 作用在方法的声明上,表示如果抛出异常,则由该方法的调用者来进行异常处理。
  2. 主要的声明这个方法会抛出会抛出某种类型的异常,让它的使用者知道捕获异常的类型。
  3. 出现异常是一种可能性,但不一定会发生异常。

42.try-catch-finally 中哪个部分可以省略?

catch和finally都可以省略,但是他们不能同时省略,可以用try catch、try finally、 try catch finally

参考https://blog.csdn.net/weixin_42924812/article/details/105210908

43.try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

finally的作用就是,无论出现什么状况,finally里的代码一定会被执行。

如果在catch中return了,也会在return之前,先执行finally代码块。

而且如果finally代码块中含有return语句,会覆盖其他地方的return。

对于基本数据类型的数据,在finally块中改变return的值对返回值没有影响,而对引用数据类型的数据会有影响。

以下四种情况finally不会执行:

  1. 在 finally 语句块第一行发生了异常。 因为在其他行,finally 块还是会得到执行
  2. 在前面的代码中用了 System.exit(int)已退出程序。 exit 是带参函数 ;若该语句在异常语句之后,finally 会执行
  3. 程序所在的线程死亡。
  4. 关闭 CPU。

参考https://blog.csdn.net/weixin_42924812/article/details/105210908

44.常见的异常类有哪些?

在 Java 中,所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。Throwable: 有两个重要的子类:Exception(异常) 和 Error(错误) ,二者都是 Java 异常处理的重要子类,各自都包含大量子类。

Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java 虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。

这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如 Java 虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java 中,错误通过 Error 的子类描述。

Exception(异常):是程序本身可以处理的异常。Exception 类有一个重要的子类 RuntimeException。RuntimeException 异常由 Java 虚拟机抛出。NullPointerException(要访问的变量没有引用任何对象时,抛出该异常)、ArithmeticException(算术运算异常,一个整数除以 0 时,抛出该异常)和 ArrayIndexOutOfBoundsException (下标越界异常)。

(1)NullPointerException 当应用程序试图访问空对象时,则抛出该异常。

(2)SQLException 提供关于数据库访问错误或其他错误信息的异常。

(3)IndexOutOfBoundsException指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。 

(4)NumberFormatException当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。

(5)FileNotFoundException当试图打开指定路径名表示的文件失败时,抛出此异常。

(6)IOException当发生某种I/O异常时,抛出此异常。此类是失败或中断的I/O操作生成的异常的通用类。

(7)ClassCastException当试图将对象强制转换为不是实例的子类时,抛出该异常。

(8)ArrayStoreException试图将错误类型的对象存储到一个对象数组时抛出的异常。

(9)IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数。

(10)ArithmeticException当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。 

(11)NegativeArraySizeException如果应用程序试图创建大小为负的数组,则抛出该异常。

(12)NoSuchMethodException无法找到某一特定方法时,抛出该异常。

(13)SecurityException由安全管理器抛出的异常,指示存在安全侵犯。

(14)UnsupportedOperationException当不支持请求的操作时,抛出该异常。

(15)RuntimeExceptionRuntimeException 是那些可能在Java虚拟机正常运行期间抛出的异常的超类。

45.static关键字

  1. 修饰成员变量和成员方法: 被 static 修饰的成员属于类,不属于单个这个类的某个对象,被类中所有对象共享,可以并且建议通过类名调用。被static 声明的成员变量属于静态成员变量,静态变量 存放在 Java 内存区域的方法区。调用格式:类名.静态变量名 类名.静态方法名()
  2. 静态代码块: 静态代码块定义在类中方法外, 静态代码块在非静态代码块之前执行(静态代码块—>非静态代码块—>构造方法)。 该类不管创建多少对象,静态代码块只执行一次.
  3. 静态内部类(static修饰类的话只能修饰内部类): 静态内部类与非静态内部类之间存在一个最大的区别: 非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类,但是静态内部类却没有。没有这个引用就意味着:1. 它的创建是不需要依赖外围类的创建。2. 它不能使用任何外围类的非static成员变量和方法。
  4. 静态导包(用来导入类中的静态资源,1.5之后的新特性): 格式为:import static 这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名调用类中静态成员,可以直接使用类中静态成员变量和成员方法。

46.java的值传递

  • 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型》
  • 一个方法可以改变一个对象参数的状态。
  • 一个方法不能让对象参数引用一个新的对象。

值传递:指的是在方法调用时,传递的参数是按值的拷贝传递,传递的是值的拷贝,也就是说传递后就互不相关了。

引用传递:指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引用的地址,也就是变量所对应的内存空间的地址。传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)。

47.Java对象的初始化顺序?

48.枚举

49.注解

50.Array.asList的用法

参考https://www.zhihu.com/question/49196023/answer/114734606

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值