为您推荐:
精华内容
最热下载
问答
  • 5星
    2.59MB qq_21193587 2021-06-02 21:09:00
  • 5星
    15.9MB Yao__Shun__Yu 2021-01-26 09:52:27
  • 5星
    46KB qq_41934573 2021-04-25 14:50:41
  • 5星
    89KB qq_43490991 2021-03-28 12:32:58
  • 5星
    27.54MB qq_35698714 2021-03-27 15:59:59
  • 5星
    28KB admin_maxin 2021-09-01 23:09:43
  • 5星
    144KB qq_41359358 2021-01-15 15:46:20
  • 5星
    1.06MB admin_maxin 2021-09-01 23:08:17
  • 5星
    8.2MB Yao__Shun__Yu 2021-08-11 16:32:43
  • 17KB m0_52957036 2020-09-17 21:54:32
  • Java容器框架中有两个名称分别为Collection和Set的接口2.list,map,set,array,它们有什么区别 (推荐学习:java实习生面试题)List接口主要有三个实现类:LinkedList,ArrayList,Vector.LinkedList:底层基于链表实现,...

    8e2e94a07b9d9e52425d6294263534a3.png

    1.Java容器框架有哪些?

    Java容器框架中有两个名称分别为Collection和Set的接口

    2.list,map,set,array,它们有什么区别 (推荐学习:java实习生面试题)

    List接口主要有三个实现类:LinkedList,ArrayList,Vector.

    LinkedList:底层基于链表实现,链表内存是散乱的,每一个元素存储本身内存地址的同时还存储下一个元素的地址

    ArrayList和Vector的区别:ArrayList是非线程安全的,效率高;Vector是基于线程安全的,效率低。

    1)Set接口主要有两个实现类:HashSet(底层由HashMap实现)和LinkedHashSet

    2)Map接口主要实现类:HashMap,HashTable和LinkedHashMap

    HashMap非线程安全,高效,支持NULL;HashTable线程安全,低效,不支持NULL

    Array:数组,可以存储对象和基本数据类型,长度固定。

    List:元素有序,可重复.

    Set:元素无序,不重复,无索引。

    Map:双列集合,用于存放键值对。键值是唯一的,不可重复。

    3.collection与collections有什么不同

    a.javutil.Collection是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。

    b.java.util.Collections是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。

    4.string,stringbuilder,stringbuffer有什么区别

    程序中用到的字符串可以分为两大类:一类是创建之后不会再做修改和变动的字符串变量;另一种是创建之后允许再做修改的字符串变量。

    对于前一种字符串变量,由于程序中经常需要对它做比较、搜索之类的操作,所以通常把它放在一个具有一定名称的对象之中,由于程序完成对该对象的上述操作,在Java程序中存放这种字符串变量是String类变量;

    对于后一种字符串变量,由于程序中经常需要对它做添加、插入、修改之类的操作,所以这种字符串变量一般都存放在StringBuilder类的对象之中。

    String 字符串变量 ,

    StringBuffer字符串变量(线程安全),

    StringBuilder字符串变量(非线程安全)

    5.==与equals有什么区别

    程序中比较两个字符时,使用关系运算符”==”,而比较两个字符串时,则需使用equals()方法。

    6.&和&&的区别

    &&是简洁运算符,&是非简洁运算符。简洁运算符(&&,||)与非简洁运算符(&,|)的区别在于:非简洁运算在必须计算完左右两个表达式之后,才取结果值;而简洁表达式可能只计算左边的表达式而不计算右边的表达式,即对于表达式&&,只要左边表达式为false,就不计算右边表达式,则整个表达式为false;对于||,只要左边表达式为true,就不计算右边表达式,则整个表达式为true.

    7.程序,进程和线程的区别

    1)程序是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码。

    2)进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个程序从创建、运行到消亡的过程。简单地说,一个进程就是一个执行中地程序,它在计算机中一个指令接着一个指令地执行,同时,每个进程还占有某些系统资源,如CPU时间、内存空间、文件、输入输出设备地使用权等等。

    3)线程:其实与进程相似,也是一个执行中地程序,但是线程是一个比进程更小地执行单位。一个进程在执行过程中可以产生多个线程,形成多条执行执行路径。但是与进程不同的是,同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换的工作时,负担要比进程小得多,也正因为如此,也正因为如此,线程也被称为轻量级进程。

    8.线程有哪几种状态?

    新建状态、就绪状态、运行状态、阻塞状态、消亡状态这五种状态

    9.线程的互斥与同步的区别

    互斥是指两个或多个线程不能同时运行,而同步则是两个或多个线程的运行有先后次序的约束。

    10.线程的同步与共享数据的区别?

    共享是指线程之间对内存数据的共享,因为线程共同拥有对内存空间中数据的处理权力,这样会导致因为多个线程同时处理数据而使数据出现不一致,所以提出同步解决此问题,即同步是在共享的基础上,是针对多个线程共享会导致数据不一致而提出来的。

    同步指的是处理数据的线程不能处理其他线程当前还没处理完的数据,但是可以处理其他数据。

    11.线程同步与异步区别

    线程同步是多个线程同时访问同一资源,等待资源访问结束,浪费时间,效率低;线程同步:访问资源时在空闲等待时同时访问其他资源,实现多线程机制。

    12.Java中四舍五入有哪些方法?

    Math类中提供了三个与取整有关的方法:ceil,floor,round,这些方法的作用于它们的英文名称的含义相对应,例如:

    ceil的英文意义是天花板,该方法就表示向上取整,Math.ceil(11.3)的结果为12,Math.ceil(-11.6)的结果为-11;

    floor的英文是地板,该方法就表示向下取整,Math.floor(11.6)的结果是11,Math.floor(-11.4)的结果-12;

    最难掌握的是round方法,他表示“四舍五入”,算法为Math.floor(x+0.5),即将原来的数字加上0.5后再向下取整,所以,Math.round(11.5)的结果是12,Math.round(-11.5)的结果-11.

    Math.round( )符合这样的规律:小数点后大于5全部加,等于5正数加,小于5全不加。

    13.MVC分别指的是什么?

    M - model 模型层,通常我们写的类放在模型层

    V - View 是视图层 ,一般就说 jsp页面

    C - control 控制层,包括action,service,dao,处理相关业务逻辑

    14.类与对象的区别?

    类是对某一类事物的描述,是抽象的、概念上的定义;而对象则是实际存在的属该类事物的具体的个体,因而也称是实例。

    15.Final的用法?

    a.将一个类声明为最终类即非继承类,表示它不能其他类所继承。

    b.最终修饰符。指定此变量的值不能改变。

    c.最终修饰符。指定该方法不能被重载。

    Abstact的用法

    a.将一个类声明为抽象类,没有实现方法,需要子类提供方法的实现,所以不能创建该类的实例。

    b.抽象修饰符。指定该方法只声明方法头,而没有方法体,抽象方法需在子类中被实现。

    Static的用法

    a.静态修饰符。指定该变量被所有对象共享,即所有的实例都可使用该变量。

    b.最终修饰符。指定不需要实例化一个对象就可以调用的方法。

    16.成员变量和局部变量的区别

    类中定义的变量是成员变量,而方法中定义的变量是局部变量。

    区别:

    a.从语法形式上看,成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数;成员变量可以被public、private、static等修饰符修饰,而局部变量则不能被访问控制修饰符及static所修饰;成员变量和局部变量都可以被final所修饰。

    b.从变量在内存中的存储方式上看,成员变量是对象的一部分,而对象是存在于堆内存的,而局部变量是存在于栈内存的。

    c.从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而产生,随着方法调用的结果而自动消失。

    d.成员变量如果没有被赋初值,则会自动以类型的默认值赋值(有一种情况例外,被final修饰但没有被static修饰的成员变量必须显式地赋值);而局部变量则不会自动赋值,必须显式地赋值后才能使用。

    展开全文
    weixin_28698233 2021-02-27 08:24:15
  • 1.Java容器框架有哪些? Java容器框架中有两个名称分别为Collection和Set的接口 2.list,map,set,array,它们有什么区别 List接口主要有三个实现类:LinkedList,ArrayList,Vector. LinkedList:底层基于链表实现,...

    1.Java容器框架有哪些?

    Java容器框架中有两个名称分别为Collection和Set的接口

     2.list,map,set,array,它们有什么区别

    List接口主要有三个实现类:LinkedList,ArrayList,Vector.

    LinkedList:底层基于链表实现,链表内存是散乱的,每一个元素存储本身内存地址的同时还存储下一个元素的地址

    ArrayList和Vector的区别:ArrayList是非线程安全的,效率高;Vector是基于线程安全的,效率低。

    1)Set接口主要有两个实现类:HashSet(底层由HashMap实现)和LinkedHashSet

    2)Map接口主要实现类:HashMap,HashTable和LinkedHashMap

    HashMap非线程安全,高效,支持NULL;HashTable线程安全,低效,不支持NULL

    Array:数组,可以存储对象和基本数据类型,长度固定。

    List:元素有序,可重复.

    Set:元素无序,不重复,无索引。

    Map:双列集合,用于存放键值对。键值是唯一的,不可重复。

    3.collection与collections有什么不同

    a.javutil.Collection是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。

    b.java.util.Collections是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。

    4.string,stringbuilder,stringbuffer有什么区别

    程序中用到的字符串可以分为两大类:一类是创建之后不会再做修改和变动的字符串变量;另一种是创建之后允许再做修改的字符串变量。对于前一种字符串变量,由于程序中经常需要对它做比较、搜索之类的操作,所以通常把它放在一个具有一定名称的对象之中,由于程序完成对该对象的上述操作,在Java程序中存放这种字符串变量是String类变量;对于后一种字符串变量,由于程序中经常需要对它做添加、插入、修改之类的操作,所以这种字符串变量一般都存放在StringBuilder类的对象之中。

    String 字符串变量

    StringBuffer字符串变量(线程安全),

    StringBuilder字符串变量(非线程安全)

    5==与equals有什么区别

    程序中比较两个字符时,使用关系运算符”==”,而比较两个字符串时,则需使用equals()方法。

    6.&和&&的区别

    &&是简洁运算符,&是非简洁运算符。简洁运算符(&&,||)与非简洁运算符(&,|)的区别在于:非简洁运算在必须计算完左右两个表达式之后,才取结果值;而简洁表达式可能只计算左边的表达式而不计算右边的表达式,即对于表达式&&,只要左边表达式为false,就不计算右边表达式,则整个表达式为false;对于||,只要左边表达式为true,就不计算右边表达式,则整个表达式为true.

    7.程序,进程和线程的区别

    1)程序是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码。

    2)进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个程序从创建、运行到消亡的过程。简单地说,一个进程就是一个执行中地程序,它在计算机中一个指令接着一个指令地执行,同时,每个进程还占有某些系统资源,如CPU时间、内存空间、文件、输入输出设备地使用权等等。

    3)线程:其实与进程相似,也是一个执行中地程序,但是线程是一个比进程更小地执行单位。一个进程在执行过程中可以产生多个线程,形成多条执行执行路径。但是与进程不同的是,同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换的工作时,负担要比进程小得多,也正因为如此,也正因为如此,线程也被称为轻量级进程。

    8.线程有哪几种状态?

    新建状态、就绪状态、运行状态、阻塞状态、消亡状态这五种状态

    9.线程的互斥与同步的区别

    互斥是指两个或多个线程不能同时运行,而同步则是两个或多个线程的运行有先后次序的约束。

    10.线程的同步与共享数据的区别?

    共享是指线程之间对内存数据的共享,因为线程共同拥有对内存空间中数据的处理权力,这样会导致因为多个线程同时处理数据而使数据出现不一致,所以提出同步解决此问题,即同步是在共享的基础上,是针对多个线程共享会导致数据不一致而提出来的。

    同步指的是处理数据的线程不能处理其他线程当前还没处理完的数据,但是可以处理其他数据。

    11.线程同步与异步区别

    线程同步是多个线程同时访问同一资源,等待资源访问结束,浪费时间,效率低;线程同步:访问资源时在空闲等待时同时访问其他资源,实现多线程机制。

    12.Java中四舍五入有哪些方法?

    Math类中提供了三个与取整有关的方法:ceil,floor,round,这些方法的作用于它们的英文名称的含义相对应,例如:ceil的英文意义是天花板,该方法就表示向上取整,Math.ceil(11.3)的结果为12,Math.ceil(-11.6)的结果为-11;floor的英文是地板,该方法就表示向下取整,Math.floor(11.6)的结果是11,Math.floor(-11.4)的结果-12;最难掌握的是round方法,他表示“四舍五入”,算法为Math.floor(x+0.5),即将原来的数字加上0.5后再向下取整,所以,Math.round(11.5)的结果是12,Math.round(-11.5)的结果-11.

    Math.round( )符合这样的规律:小数点后大于5全部加,等于5正数加,小于5全不加。

    13.MVC分别指的是什么?

    M - model 模型层,通常我们写的类放在模型层
    V - View 是视图层 ,一般就说 jsp页面
    C - control 控制层,包括action,service,dao,处理相关业务逻辑

    14.类与对象的区别?

    类是对某一类事物的描述,是抽象的、概念上的定义;而对象则是实际存在的属该类事物的具体的个体,因而也称是实例。

    15Final的用法?

    a.将一个类声明为最终类即非继承类,表示它不能其他类所继承。

    b.最终修饰符。指定此变量的值不能改变。

    c.最终修饰符。指定该方法不能被重载。

    15Abstact的用法

    a.将一个类声明为抽象类,没有实现方法,需要子类提供方法的实现,所以不能创建该类的实例。

    b.抽象修饰符。指定该方法只声明方法头,而没有方法体,抽象方法需在子类中被实现。

    16.Static的用法

    a.静态修饰符。指定该变量被所有对象共享,即所有的实例都可使用该变量。

    b.最终修饰符。指定不需要实例化一个对象就可以调用的方法。

    16.成员变量和局部变量的区别

    类中定义的变量是成员变量,而方法中定义的变量是局部变量。

    区别:

    a.从语法形式上看,成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数;成员变量可以被public、private、static等修饰符修饰,而局部变量则不能被访问控制修饰符及static所修饰;成员变量和局部变量都可以被final所修饰。

    b.从变量在内存中的存储方式上看,成员变量是对象的一部分,而对象是存在于堆内存的,而局部变量是存在于栈内存的。

    c.从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而产生,随着方法调用的结果而自动消失。

    d.成员变量如果没有被赋初值,则会自动以类型的默认值赋值(有一种情况例外,被final修饰但没有被static修饰的成员变量必须显式地赋值);而局部变量则不会自动赋值,必须显式地赋值后才能使用。

     

     

     

     

     

     

     

     

    展开全文
    baidu_39212797 2019-03-17 22:04:43
  • java实习生面试题大全(2019年整理)标准SQL语法及语句一道关于group bySQL 语句面试题表中有A B C 三列,用SQL 语句实现:当A 列大于B 列时选择A 列否则选择B 列,当B列大于C列时 选择B 列否则选择C 列请用一条sql ...

    java实习生面试题大全(2019年整理)

    标准SQL语法及语句

    一道关于group bySQL 语句面试题

    表中有A B C 三列,用SQL 语句实现:当A 列大于B 列时选择A 列否则选择B 列,当B列大于C列时 选择B 列否则选择C 列

    请用一条sql 语句查询出这三条记录并按以下条件显示出来

    华为面试题:一个表中的Id有多个记录,把所有这个id的记录查出来,并显示共有多少条记录数

    如何优化数据库,如何提高数据库的性能?

    表与表之间的关联关系

    主键和外键的区别

    描述一下你最常用的java编程风格

    维护数据库的完整性、一致性、你喜欢用触发器还是自写业务逻辑?为什么?

    什么是事务?什么是锁?

    什么是索引,有什么优点?

    视图是什么?游标是什么?

    什么是存储过程?有什么优点?

    触发器的作用?

    什么是内存泄漏?

    790fe0f25ec3a3a90fe759643b6b130b.pngjava实习生面试题大全

    sql Server中float、real、decimal(numeric)数据类型的区别

    sqlserver中nchar(n)、nvarchar(n)、ntext有什么区别?

    sqlserver中char(n)、varchar(n)、text有什么区别?

    Static Nested Class 和 Inner Class的不同

    设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1

    接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)?

    请说出你所知道的线程同步的方法

    多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?

    线程的基本概念、线程的基本状态以及状态之间的关系

    如果变量用final修饰,则怎样?如果方法final修饰,则怎样?

    java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用?

    作用域public,private,protected,以及不写时的区别

    Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实 现)interface(接口

    什么时候用assert

    Set 里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何 区别

    abstract class和interface有什么区别

    介绍JAVA 中的Collection FrameWork(包括如何写自己的数据结构)?

    JAVA 语言如何进行异常处理,关键字:throws,throw,try,catch,finally 分别代表什么意义?在try 块中可以抛出异常吗?

    请对以下在J2EE中常用的名词进行解释(或简单描述)

    web.xml文件的作用是什么?

    什么是Java SE、Java EE、Java ME?

    socket通信

    Java程序怎么优化?

    编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串

    如何校验数字型?

    Servlet的生命周期?

    什么情况下调用doGet()和doPost()?

    C/S 与B/S 区别

    什么是web容器

    什么是JNDI

    什么是JMS

    什么是JTA

    什么是JAF

    MVC的各个部分都有那些技术来实现?如何实现?

    j2ee常用的设计模式?说明工厂模式。

    说说Spring MVC Framework特点

    说说SSM优缺点及使用场景

    面向对象和面向过程的区别

    自动装箱与拆箱

    java中线程的状态转换

    JAVA 中的几种基本数据类型是什么,各自占用多少字节

    redis和memcached的区别

    sql行转列

    MySQL存储引擎- MyISAM与InnoDB区别

    java中接口有什么用

    简述Dubbo的均衡策略和集群容错模式

    深入理解Java的接口和抽象类

    说说http,https协议

    说说tcp/ip协议

    TCP与UDP的区别

    cookie和session的区别,分布式环境怎么保存用户状态

    请写一段栈溢出、堆溢出的代码

    展开全文
    weixin_31282459 2021-02-27 08:24:18
  • Java 中有三个访问权限修饰符:private、protected 以及 public,如果不加访问修饰符,表示包级可见。 可以对类或类中的成员(字段以及方法)加上访问修饰符。 类可见表示其它类可以用这个类创建实例对象。 ...

    一、数据类型

    包装类型

    八个基本类型:

    • boolean/1
    • byte/8
    • char/16
    • short/16
    • int/32
    • float/32
    • long/64
    • double/64

    基本类型都有对应的包装类型,基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。

    Integer x = 2;     // 装箱
    int y = x;         // 拆箱

    缓存池

    new Integer(123) 与 Integer.valueOf(123) 的区别在于:

    • new Integer(123) 每次都会新建一个对象
    • Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。
    Integer x = new Integer(123);
    Integer y = new Integer(123);
    System.out.println(x == y);    // false
    Integer z = Integer.valueOf(123);
    Integer k = Integer.valueOf(123);
    System.out.println(z == k);   // true

    valueOf() 方法的实现比较简单,就是先判断值是否在缓存池中,如果在的话就直接返回缓存池的内容。

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

    在 Java 8 中,Integer 缓存池的大小默认为 -128~127。

    static final int low = -128;
    static final int high;
    static final Integer cache[];
    
    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;
    
        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    
        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

    编译器会在自动装箱过程调用 valueOf() 方法,因此多个 Integer 实例使用自动装箱来创建并且值相同,那么就会引用相同的对象。

    Integer m = 123;
    Integer n = 123;
    System.out.println(m == n); // true

    基本类型对应的缓冲池如下:

    • boolean values true and false
    • all byte values
    • short values between -128 and 127
    • int values between -128 and 127
    • char in the range \u0000 to \u007F

    在使用这些基本类型对应的包装类型时,就可以直接使用缓冲池中的对象。

    StackOverflow : Differences between new Integer(123), Integer.valueOf(123) and just 123

    二、String

    概览

    String 被声明为 final,因此它不可被继承。

    内部使用 char 数组存储数据,该数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
        /** The value is used for character storage. */
        private final char value[];

    不可变的好处

    1. 可以缓存 hash 值

    因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。

    2. String Pool 的需要

    如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。

     

    3. 安全性

    String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 对象的那一方以为现在连接的是其它主机,而实际情况却不一定是。

    4. 线程安全

    String 不可变性天生具备线程安全,可以在多个线程中安全地使用。

    Program Creek : Why String is immutable in Java?

    String, StringBuffer and StringBuilder

    1. 可变性

    • String 不可变
    • StringBuffer 和 StringBuilder 可变

    2. 线程安全

    • String 不可变,因此是线程安全的
    • StringBuilder 不是线程安全的
    • StringBuffer 是线程安全的,内部使用 synchronized 进行同步

    StackOverflow : String, StringBuffer, and StringBuilder

    String.intern()

    使用 String.intern() 可以保证相同内容的字符串变量引用同一的内存对象。

    下面示例中,s1 和 s2 采用 new String() 的方式新建了两个不同对象,而 s3 是通过 s1.intern() 方法取得一个对象引用。intern() 首先把 s1 引用的对象放到 String Pool(字符串常量池)中,然后返回这个对象引用。因此 s3 和 s1 引用的是同一个字符串常量池的对象。

    String s1 = new String("aaa");
    String s2 = new String("aaa");
    System.out.println(s1 == s2);           // false
    String s3 = s1.intern();
    System.out.println(s1.intern() == s3);  // true

    如果是采用 "bbb" 这种使用双引号的形式创建字符串实例,会自动地将新建的对象放入 String Pool 中。

    String s4 = "bbb";
    String s5 = "bbb";
    System.out.println(s4 == s5);  // true

    在 Java 7 之前,字符串常量池被放在运行时常量池中,它属于永久代。而在 Java 7,字符串常量池被移到 Native Method 中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。

    三、运算

    参数传递

    Java 的参数是以值传递的形式传入方法中,而不是引用传递。

    以下代码中 Dog dog 的 dog 是一个指针,存储的是对象的地址。在将一个参数传入一个方法时,本质上是将对象的地址以值的方式传递到形参中。因此在方法中改变指针引用的对象,那么这两个指针此时指向的是完全不同的对象,一方改变其所指向对象的内容对另一方没有影响。

    public class Dog {
        String name;
    
        Dog(String name) {
            this.name = name;
        }
    
        String getName() {
            return this.name;
        }
    
        void setName(String name) {
            this.name = name;
        }
    
        String getObjectAddress() {
            return super.toString();
        }
    }
    public class PassByValueExample {
        public static void main(String[] args) {
            Dog dog = new Dog("A");
            System.out.println(dog.getObjectAddress()); // Dog@4554617c
            func(dog);
            System.out.println(dog.getObjectAddress()); // Dog@4554617c
            System.out.println(dog.getName());          // A
        }
    
        private static void func(Dog dog) {
            System.out.println(dog.getObjectAddress()); // Dog@4554617c
            dog = new Dog("B");
            System.out.println(dog.getObjectAddress()); // Dog@74a14482
            System.out.println(dog.getName());          // B
        }
    }

     但是如果在方法中改变对象的字段值会改变原对象该字段值,因为改变的是同一个地址指向的内容。

    class PassByValueExample {
        public static void main(String[] args) {
            Dog dog = new Dog("A");
            func(dog);
            System.out.println(dog.getName());          // B
        }
    
        private static void func(Dog dog) {
            dog.setName("B");
        }
    }

    StackOverflow: Is Java “pass-by-reference” or “pass-by-value”?

    float 与 double

    1.1 字面量属于 double 类型,不能直接将 1.1 直接赋值给 float 变量,因为这是向下转型。Java 不能隐式执行向下转型,因为这会使得精度降低。

    // float f = 1.1;

    1.1f 字面量才是 float 类型。

    float f = 1.1f;

    隐式类型转换

    因为字面量 1 是 int 类型,它比 short 类型精度要高,因此不能隐式地将 int 类型下转型为 short 类型。

    short s1 = 1;
    // s1 = s1 + 1;

    但是使用 += 运算符可以执行隐式类型转换。

    s1 += 1;

    上面的语句相当于将 s1 + 1 的计算结果进行了向下转型:

    s1 = (short) (s1 + 1);

    StackOverflow : Why don't Java's +=, -=, *=, /= compound assignment operators require casting?

    switch

    从 Java 7 开始,可以在 switch 条件判断语句中使用 String 对象。

    String s = "a";
    switch (s) {
        case "a":
            System.out.println("aaa");
            break;
        case "b":
            System.out.println("bbb");
            break;
    }

    switch 不支持 long,是因为 switch 的设计初衷是对那些只有少数的几个值进行等值判断,如果值过于复杂,那么还是用 if 比较合适。

    // long x = 111;
    // switch (x) { // Incompatible types. Found: 'long', required: 'char, byte, short, int, Character, Byte, Short, Integer, String, or an enum'
    //     case 111:
    //         System.out.println(111);
    //         break;
    //     case 222:
    //         System.out.println(222);
    //         break;
    // }

    StackOverflow : Why can't your switch statement data type be long, Java?

    四、继承

    访问权限

    Java 中有三个访问权限修饰符:private、protected 以及 public,如果不加访问修饰符,表示包级可见。

    可以对类或类中的成员(字段以及方法)加上访问修饰符。

    • 类可见表示其它类可以用这个类创建实例对象。
    • 成员可见表示其它类可以用这个类的实例对象访问到该成员;

    protected 用于修饰成员,表示在继承体系中成员对于子类可见,但是这个访问修饰符对于类没有意义。

    设计良好的模块会隐藏所有的实现细节,把它的 API 与它的实现清晰地隔离开来。模块之间只通过它们的 API 进行通信,一个模块不需要知道其他模块的内部工作情况,这个概念被称为信息隐藏或封装。因此访问权限应当尽可能地使每个类或者成员不被外界访问。

    如果子类的方法重写了父类的方法,那么子类中该方法的访问级别不允许低于父类的访问级别。这是为了确保可以使用父类实例的地方都可以使用子类实例,也就是确保满足里氏替换原则。

    字段决不能是公有的,因为这么做的话就失去了对这个字段修改行为的控制,客户端可以对其随意修改。例如下面的例子中,AccessExample 拥有 id 共有字段,如果在某个时刻,我们想要使用 int 去存储 id 字段,那么就需要去修改所有的客户端代码。

    public class AccessExample {
        public String id;
    }

    可以使用公有的 getter 和 setter 方法来替换公有字段,这样的话就可以控制对字段的修改行为。

    public class AccessExample {
    
        private int id;
    
        public String getId() {
            return id + "";
        }
    
        public void setId(String id) {
            this.id = Integer.valueOf(id);
        }
    }

    但是也有例外,如果是包级私有的类或者私有的嵌套类,那么直接暴露成员不会有特别大的影响。

    public class AccessWithInnerClassExample {
        private class InnerClass {
            int x;
        }
    
        private InnerClass innerClass;
    
        public AccessWithInnerClassExample() {
            innerClass = new InnerClass();
        }
    
        public int getValue() {
            return innerClass.x;  // 直接访问
        }
    }

    抽象类与接口

    1. 抽象类

    抽象类和抽象方法都使用 abstract 关键字进行声明。抽象类一般会包含抽象方法,抽象方法一定位于抽象类中。

    抽象类和普通类最大的区别是,抽象类不能被实例化,需要继承抽象类才能实例化其子类。

    public abstract class AbstractClassExample {
    
        protected int x;
        private int y;
    
        public abstract void func1();
    
        public void func2() {
            System.out.println("func2");
        }
    }
    public class AbstractExtendClassExample extends AbstractClassExample {
        @Override
        public void func1() {
            System.out.println("func1");
        }
    }
    // AbstractClassExample ac1 = new AbstractClassExample(); // 'AbstractClassExample' is abstract; cannot be instantiated
    AbstractClassExample ac2 = new AbstractExtendClassExample();
    ac2.func1();

    2. 接口

    接口是抽象类的延伸,在 Java 8 之前,它可以看成是一个完全抽象的类,也就是说它不能有任何的方法实现。

    从 Java 8 开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在 Java 8 之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类。

    接口的成员(字段 + 方法)默认都是 public 的,并且不允许定义为 private 或者 protected。

    接口的字段默认都是 static 和 final 的。

    public interface InterfaceExample {
        void func1();
    
        default void func2(){
            System.out.println("func2");
        }
    
        int x = 123;
        // int y;               // Variable 'y' might not have been initialized
        public int z = 0;       // Modifier 'public' is redundant for interface fields
        // private int k = 0;   // Modifier 'private' not allowed here
        // protected int l = 0; // Modifier 'protected' not allowed here
        // private void fun3(); // Modifier 'private' not allowed here
    }
    public class InterfaceImplementExample implements InterfaceExample {
        @Override
        public void func1() {
            System.out.println("func1");
        }
    }
    // InterfaceExample ie1 = new InterfaceExample(); // 'InterfaceExample' is abstract; cannot be instantiated
    InterfaceExample ie2 = new InterfaceImplementExample();
    ie2.func1();
    System.out.println(InterfaceExample.x);

    3. 比较

    • 从设计层面上看,抽象类提供了一种 IS-A 关系,那么就必须满足里式替换原则,即子类对象必须能够替换掉所有父类对象。而接口更像是一种 LIKE-A 关系,它只是提供一种方法实现契约,并不要求接口和实现接口的类具有 IS-A 关系。
    • 从使用上来看,一个类可以实现多个接口,但是不能继承多个抽象类。
    • 接口的字段只能是 static 和 final 类型的,而抽象类的字段没有这种限制。
    • 接口的成员只能是 public 的,而抽象类的成员可以有多种访问权限。

    4. 使用选择

    使用接口:

    • 需要让不相关的类都实现一个方法,例如不相关的类都可以实现 Compareable 接口中的 compareTo() 方法;
    • 需要使用多重继承。

    使用抽象类:

    • 需要在几个相关的类中共享代码。
    • 需要能控制继承来的成员的访问权限,而不是都为 public。
    • 需要继承非静态和非常量字段。

    在很多情况下,接口优先于抽象类,因为接口没有抽象类严格的类层次结构要求,可以灵活地为一个类添加行为。并且从 Java 8 开始,接口也可以有默认的方法实现,使得修改接口的成本也变的很低。

    super

    • 访问父类的构造函数:可以使用 super() 函数访问父类的构造函数,从而委托父类完成一些初始化的工作。
    • 访问父类的成员:如果子类重写了父类的中某个方法的实现,可以通过使用 super 关键字来引用父类的方法实现。
    public class SuperExample {
        protected int x;
        protected int y;
    
        public SuperExample(int x, int y) {
            this.x = x;
            this.y = y;
        }
    
        public void func() {
            System.out.println("SuperExample.func()");
        }
    }
    public class SuperExtendExample extends SuperExample {
        private int z;
    
        public SuperExtendExample(int x, int y, int z) {
            super(x, y);
            this.z = z;
        }
    
        @Override
        public void func() {
            super.func();
            System.out.println("SuperExtendExample.func()");
        }
    }
    SuperExample e = new SuperExtendExample(1, 2, 3);
    e.func();
    SuperExample.func()
    SuperExtendExample.func()

    Using the Keyword super

    重写与重载

    1. 重写(Override)

    存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法。

    为了满足里式替换原则,重写有有以下两个限制:

    • 子类方法的访问权限必须大于等于父类方法;
    • 子类方法的返回类型必须是父类方法返回类型或为其子类型。

    使用 @Override 注解,可以让编译器帮忙检查是否满足上面的两个限制条件。

    2. 重载(Overload)

    存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数类型、个数、顺序至少有一个不同。

    应该注意的是,返回值不同,其它都相同不算是重载。

    五、Object 通用方法

    概览

    public final native Class<?> getClass()
    
    public native int hashCode()
    
    public boolean equals(Object obj)
    
    protected native Object clone() throws CloneNotSupportedException
    
    public String toString()
    
    public final native void notify()
    
    public final native void notifyAll()
    
    public final native void wait(long timeout) throws InterruptedException
    
    public final void wait(long timeout, int nanos) throws InterruptedException
    
    public final void wait() throws InterruptedException
    
    protected void finalize() throws Throwable {}

    equals()

    1. 等价关系

    (一)自反性

    x.equals(x); // true

    (二)对称性

    x.equals(y) == y.equals(x); // true

    (三)传递性

    if (x.equals(y) && y.equals(z))
        x.equals(z); // true;

    (四)一致性

    多次调用 equals() 方法结果不变

    x.equals(y) == x.equals(y); // true

    (五)与 null 的比较

    对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false

    x.equals(null); // false;

    2. equals() 与 ==

    • 对于基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。
    • 对于引用类型,== 判断两个变量是否引用同一个对象,而 equals() 判断引用的对象是否等价。
    Integer x = new Integer(1);
    Integer y = new Integer(1);
    System.out.println(x.equals(y)); // true
    System.out.println(x == y);      // false

    3. 实现

    • 检查是否为同一个对象的引用,如果是直接返回 true;
    • 检查是否是同一个类型,如果不是,直接返回 false;
    • 将 Object 对象进行转型;
    • 判断每个关键域是否相等。
    public class EqualExample {
        private int x;
        private int y;
        private int z;
    
        public EqualExample(int x, int y, int z) {
            this.x = x;
            this.y = y;
            this.z = z;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            EqualExample that = (EqualExample) o;
    
            if (x != that.x) return false;
            if (y != that.y) return false;
            return z == that.z;
        }
    }

    hashCode()

    hasCode() 返回散列值,而 equals() 是用来判断两个对象是否等价。等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。

    在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等。

    下面的代码中,新建了两个等价的对象,并将它们添加到 HashSet 中。我们希望将这两个对象当成一样的,只在集合中添加一个对象,但是因为 EqualExample 没有实现 hasCode() 方法,因此这两个对象的散列值是不同的,最终导致集合添加了两个等价的对象。

    EqualExample e1 = new EqualExample(1, 1, 1);
    EqualExample e2 = new EqualExample(1, 1, 1);
    System.out.println(e1.equals(e2)); // true
    HashSet<EqualExample> set = new HashSet<>();
    set.add(e1);
    set.add(e2);
    System.out.println(set.size());   // 2

    理想的散列函数应当具有均匀性,即不相等的对象应当均匀分布到所有可能的散列值上。这就要求了散列函数要把所有域的值都考虑进来,可以将每个域都当成 R 进制的某一位,然后组成一个 R 进制的整数。R 一般取 31,因为它是一个奇素数,如果是偶数的话,当出现乘法溢出,信息就会丢失,因为与 2 相乘相当于向左移一位。

    一个数与 31 相乘可以转换成移位和减法:31*x == (x<<5)-x,编译器会自动进行这个优化。

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + x;
        result = 31 * result + y;
        result = 31 * result + z;
        return result;
    }

    toString()

    默认返回 ToStringExample@4554617c 这种形式,其中 @ 后面的数值为散列码的无符号十六进制表示。

    public class ToStringExample {
        private int number;
    
        public ToStringExample(int number) {
            this.number = number;
        }
    }
    ToStringExample example = new ToStringExample(123);
    System.out.println(example.toString());
    ToStringExample@4554617c

    clone()

    1. cloneable

    clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。

    public class CloneExample {
        private int a;
        private int b;
    }
    CloneExample e1 = new CloneExample();
    // CloneExample e2 = e1.clone(); // 'clone()' has protected access in 'java.lang.Object'

    重写 clone() 得到以下实现:

    public class CloneExample {
        private int a;
        private int b;
    
        @Override
        protected CloneExample clone() throws CloneNotSupportedException {
            return (CloneExample)super.clone();
        }
    }
    CloneExample e1 = new CloneExample();
    try {
        CloneExample e2 = e1.clone();
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
    java.lang.CloneNotSupportedException: CloneExample

    以上抛出了 CloneNotSupportedException,这是因为 CloneExample 没有实现 Cloneable 接口。

    应该注意的是,clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。

    public class CloneExample implements Cloneable {
        private int a;
        private int b;
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }

    2. 浅拷贝

    拷贝对象和原始对象的引用类型引用同一个对象。

    public class ShallowCloneExample implements Cloneable {
        private int[] arr;
    
        public ShallowCloneExample() {
            arr = new int[10];
            for (int i = 0; i < arr.length; i++) {
                arr[i] = i;
            }
        }
    
        public void set(int index, int value) {
            arr[index] = value;
        }
    
        public int get(int index) {
            return arr[index];
        }
    
        @Override
        protected ShallowCloneExample clone() throws CloneNotSupportedException {
            return (ShallowCloneExample) super.clone();
        }
    }
    ShallowCloneExample e1 = new ShallowCloneExample();
    ShallowCloneExample e2 = null;
    try {
        e2 = e1.clone();
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
    e1.set(2, 222);
    System.out.println(e2.get(2)); // 222

     3. 深拷贝

    拷贝对象和原始对象的引用类型引用不同对象。

    public class DeepCloneExample implements Cloneable {
        private int[] arr;
    
        public DeepCloneExample() {
            arr = new int[10];
            for (int i = 0; i < arr.length; i++) {
                arr[i] = i;
            }
        }
    
        public void set(int index, int value) {
            arr[index] = value;
        }
    
        public int get(int index) {
            return arr[index];
        }
    
        @Override
        protected DeepCloneExample clone() throws CloneNotSupportedException {
            DeepCloneExample result = (DeepCloneExample) super.clone();
            result.arr = new int[arr.length];
            for (int i = 0; i < arr.length; i++) {
                result.arr[i] = arr[i];
            }
            return result;
        }
    }
    DeepCloneExample e1 = new DeepCloneExample();
    DeepCloneExample e2 = null;
    try {
        e2 = e1.clone();
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
    e1.set(2, 222);
    System.out.println(e2.get(2)); // 2

     4. clone() 的替代方案

    使用 clone() 方法来拷贝一个对象即复杂又有风险,它会抛出异常,并且还需要类型转换。Effective Java 书上讲到,最好不要去使用 clone(),可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。

    public class CloneConstructorExample {
        private int[] arr;
    
        public CloneConstructorExample() {
            arr = new int[10];
            for (int i = 0; i < arr.length; i++) {
                arr[i] = i;
            }
        }
    
        public CloneConstructorExample(CloneConstructorExample original) {
            arr = new int[original.arr.length];
            for (int i = 0; i < original.arr.length; i++) {
                arr[i] = original.arr[i];
            }
        }
    
        public void set(int index, int value) {
            arr[index] = value;
        }
    
        public int get(int index) {
            return arr[index];
        }
    }
    CloneConstructorExample e1 = new CloneConstructorExample();
    CloneConstructorExample e2 = new CloneConstructorExample(e1);
    e1.set(2, 222);
    System.out.println(e2.get(2)); // 2

    六、关键字

    final

    1. 数据

    声明数据为常量,可以是编译时常量,也可以是在运行时被初始化后不能被改变的常量。

    • 对于基本类型,final 使数值不变;
    • 对于引用类型,final 使引用不变,也就不能引用其它对象,但是被引用的对象本身是可以修改的。
    final int x = 1;
    // x = 2;  // cannot assign value to final variable 'x'
    final A y = new A();
    y.a = 1;

    2. 方法

    声明方法不能被子类重写。

    private 方法隐式地被指定为 final,如果在子类中定义的方法和基类中的一个 private 方法签名相同,此时子类的方法不是重写基类方法,而是在子类中定义了一个新的方法。

    3. 类

    声明类不允许被继承。

    static

    1. 静态变量

    • 静态变量:又称为类变量,也就是说这个变量属于类的,类所有的实例都共享静态变量,可以直接通过类名来访问它;静态变量在内存中只存在一份。
    • 实例变量:每创建一个实例就会产生一个实例变量,它与该实例同生共死。
    public class A {
        private int x;         // 实例变量
        private static int y;  // 静态变量
    
        public static void main(String[] args) {
            // int x = A.x;  // Non-static field 'x' cannot be referenced from a static context
            A a = new A();
            int x = a.x;
            int y = A.y;
        }
    }

    2. 静态方法

    静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法(abstract)。

    public abstract class A {
        public static void func1(){
        }
        // public abstract static void func2();  // Illegal combination of modifiers: 'abstract' and 'static'
    }

    只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字。

    public class A {
        private static int x;
        private int y;
    
        public static void func1(){
            int a = x;
            // int b = y;  // Non-static field 'y' cannot be referenced from a static context
            // int b = this.y;     // 'A.this' cannot be referenced from a static context
        }
    }

    3. 静态语句块

    静态语句块在类初始化时运行一次。

    public class A {
        static {
            System.out.println("123");
        }
    
        public static void main(String[] args) {
            A a1 = new A();
            A a2 = new A();
        }
    }
    123

    4. 静态内部类

    非静态内部类依赖于外部类的实例,而静态内部类不需要。

    public class OuterClass {
        class InnerClass {
        }
    
        static class StaticInnerClass {
        }
    
        public static void main(String[] args) {
            // InnerClass innerClass = new InnerClass(); // 'OuterClass.this' cannot be referenced from a static context
            OuterClass outerClass = new OuterClass();
            InnerClass innerClass = outerClass.new InnerClass();
            StaticInnerClass staticInnerClass = new StaticInnerClass();
        }
    }

    静态内部类不能访问外部类的非静态的变量和方法。

    5. 静态导包

    在使用静态变量和方法时不用再指明 ClassName,从而简化代码,但可读性大大降低。

    import static com.xxx.ClassName.*

    6. 初始化顺序

    静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序。

    public static String staticField = "静态变量";
    static {
        System.out.println("静态语句块");
    }
    public String field = "实例变量";
    {
        System.out.println("普通语句块");
    }

    最后才是构造函数的初始化。

    public InitialOrderTest() {
        System.out.println("构造函数");
    }

    存在继承的情况下,初始化顺序为:

    • 父类(静态变量、静态语句块)
    • 子类(静态变量、静态语句块)
    • 父类(实例变量、普通语句块)
    • 父类(构造函数)
    • 子类(实例变量、普通语句块)
    • 子类(构造函数)

    七、反射

    每个类都有一个 Class 对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。

    类加载相当于 Class 对象的加载。类在第一次使用时才动态加载到 JVM 中,可以使用 Class.forName("com.mysql.jdbc.Driver") 这种方式来控制类的加载,该方法会返回一个 Class 对象。

    反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时期该类的 .class 不存在也可以加载进来。

    Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:

    • Field :可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
    • Method :可以使用 invoke() 方法调用与 Method 对象关联的方法;
    • Constructor :可以用 Constructor 创建新的对象。

    Advantages of Using Reflection:

    • Extensibility Features : An application may make use of external, user-defined classes by creating instances of extensibility objects using their fully-qualified names.
    • Class Browsers and Visual Development Environments : A class browser needs to be able to enumerate the members of classes. Visual development environments can benefit from making use of type information available in reflection to aid the developer in writing correct code.
    • Debuggers and Test Tools : Debuggers need to be able to examine private members on classes. Test harnesses can make use of reflection to systematically call a discoverable set APIs defined on a class, to insure a high level of code coverage in a test suite.

    Drawbacks of Reflection:

    Reflection is powerful, but should not be used indiscriminately. If it is possible to perform an operation without using reflection, then it is preferable to avoid using it. The following concerns should be kept in mind when accessing code via reflection.

    • Performance Overhead : Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.

    • Security Restrictions : Reflection requires a runtime permission which may not be present when running under a security manager. This is in an important consideration for code which has to run in a restricted security context, such as in an Applet.

    • Exposure of Internals :Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform.

    • Trail: The Reflection API

    • 深入解析 Java 反射(1)- 基础

    八、异常

    Throwable 可以用来表示任何可以作为异常抛出的类,分为两种: Error 和 Exception。其中 Error 用来表示 JVM 无法处理的错误,Exception 分为两种:

    • 受检异常 :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
    • 非受检异常 :是程序运行时错误,例如除 0 会引发 Arithmetic Exception,此时程序崩溃并且无法恢复。

     

    九、泛型

    public class Box<T> {
        // T stands for "Type"
        private T t;
        public void set(T t) { this.t = t; }
        public T get() { return t; }
    }

    十、注解

    Java 注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。

    注解 Annotation 实现原理与自定义注解例子

    十一、特性

    Java 各版本的新特性

    New highlights in Java SE 8

    1. Lambda Expressions
    2. Pipelines and Streams
    3. Date and Time API
    4. Default Methods
    5. Type Annotations
    6. Nashhorn JavaScript Engine
    7. Concurrent Accumulators
    8. Parallel operations
    9. PermGen Error Removed

    New highlights in Java SE 7

    1. Strings in Switch Statement
    2. Type Inference for Generic Instance Creation
    3. Multiple Exception Handling
    4. Support for Dynamic Languages
    5. Try with Resources
    6. Java nio Package
    7. Binary Literals, Underscore in literals
    8. Diamond Syntax

    Java 与 C++ 的区别

    • Java 是纯粹的面向对象语言,所有的对象都继承自 java.lang.Object,C++ 为了兼容 C 即支持面向对象也支持面向过程。
    • Java 通过虚拟机从而实现跨平台特性,但是 C++ 依赖于特定的平台。
    • Java 没有指针,它的引用可以理解为安全指针,而 C++ 具有和 C 一样的指针。
    • Java 支持自动垃圾回收,而 C++ 需要手动回收。
    • Java 不支持多重继承,只能通过实现多个接口来达到相同目的,而 C++ 支持多重继承。
    • Java 不支持操作符重载,虽然可以对两个 String 对象支持加法运算,但是这是语言内置支持的操作,不属于操作符重载,而 C++ 可以。
    • Java 的 goto 是保留字,但是不可用,C++ 可以使用 goto。
    • Java 不支持条件编译,C++ 通过 #ifdef #ifndef 等预处理命令从而实现条件编译。

    What are the main differences between Java and C++?

    JRE or JDK

    • JRE is the JVM program, Java application need to run on JRE.
    • JDK is a superset of JRE, JRE + tools for developing java programs. e.g, it provides the compiler "javac"

    参考资料

    • Eckel B. Java 编程思想[M]. 机械工业出版社, 2002.
    • Bloch J. Effective java[M]. Addison-Wesley Professional, 2017.

    我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。 

    展开全文
    qq_41701956 2018-09-14 10:16:34
  • xx666zz 2018-11-09 13:20:00
  • weixin_43401042 2020-12-11 15:20:03
  • inpunt 2019-03-05 14:48:16
  • qf2019 2020-03-06 10:25:50
  • weixin_39777637 2021-03-07 03:00:07
  • Smuen 2021-06-12 08:15:19
  • 4星
    76KB a285699732 2012-04-30 20:15:53
  • weixin_36292971 2021-03-04 00:02:22
  • asdsam1230 2019-10-02 10:41:44
  • 19KB Feng_wwf 2020-09-05 11:06:38
  • qq_45266900 2020-12-30 17:57:27
  • weixin_42159145 2021-07-27 14:21:54
  • qq_39475829 2021-03-29 15:13:06
  • LOOPY2021 2021-09-23 18:08:49

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,877
精华内容 5,150
关键字:

java实习生面试题

java 订阅
友情链接: LAB6.zip