Java中,2020最新版

日期:2020-03-31 23:08:11 来源:互联网 编辑:小优 阅读人数:454

Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程 。

JVM Java Virtual Machine是Java虚拟机,Java程序需要运行在虚拟机上,不同的平台有自己的虚拟机,因此Java语言可以实现跨平台。

JRE Java Runtime Environment包括Java虚拟机和Java程序所需的核心类库等。核心类库主要是java.lang包:包含了运行Java程序必不可少的类,如基本数据类型、基本数学函数、字符串处理、线程、异常处理类等,缺省加载这个包

如果想要运行一个好的Java程序,计算机中只需要安装JRE即可。

JDK Java Development Kit是提供给Java人员使用的,其中包含了Java的工具,也包括了JRE。所以安装了JDK,就无需再单独安装JRE了。其中的工具:编译工具(javac.exe)打包工具(jar.exe)等

Java中,2020最新版(图1)

所谓跨平台性,是指java语言编写的程序,一次编译后,可以在多个平台上运行。

实现原理:Java程序是通过java虚拟机在平台上运行的,只要该可以安装相应的java虚拟机,该就可以运行java程序。

简单易学(Java语言的语法与C语言和C++语言很接近)

面向对象(封装,继承,多态)

平台无关性(Java虚拟机实现平台无关性)

支持网络编程并且很方便(Java语言诞生本身就是为简化网络编程设计的)

支持多线程(多线程机制使应用程序在同一时间并行执行多项任)

健壮性(Java语言的强类型机制、异常处理、垃圾的自动收集等)

安全性

字节码:Java源代码经过虚拟机编译器编译后产生的文件(即扩展为.class的文件)它不面向任何特定的处理器,只面向虚拟机。

采用字节码的好处:

Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效,而且,由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。

先看下java中的编译器和解释器:

Java中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟机器。这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口。编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,由解释器来将虚拟机代码转换为特定的机器码执行。在Java中,这种供虚拟机理解的代码叫做字节码(即扩展为.class的文件)它不面向任何特定的处理器,只面向虚拟机。每一种平台的解释器是不同的,但是实现的虚拟机是相同的。Java源程序经过编译器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的机器码,在特定的机器上运行,这就是上面提到的Java的特点的编译与解释并存的解释。

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

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

我知道很多人没学过C++,但是面试官就是没事喜欢拿咱们Java和C++比呀!没办法!!就算没学过C++,也要记下来!

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

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

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

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

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

定义:Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类型,在内存中分配了不同大小的内存空间。

分类

Java中,2020最新版(图2)

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

2 << 3(左移 3 位相当于乘以 2 的 3 次方,右移 3 位相当于除以 2 的 3 次方)

Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加 0.5 进行下取整。

不正确。3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成 float f =3.4F。

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

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

Java语言采用Unicode编码标准,Unicode(标准码)它为每个字符制订了一个唯一的数值,因此在任何的语言,平台,程序都可以放心的使用。

定义:用于解释说明程序的文字

分类

作用

在程序中,尤其是复杂的程序中,适当地加入注释可以增加程序的可读性,有利于程序的修改、调试和交流。注释的内容在程序编译的时候会被忽视,不会产生目标代码,注释的部分不会对程序的执行结果产生任何影响。

注意事项:多行和文档注释都不能嵌套使用。

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

分类

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

Java中,2020最新版(图3)

&运算符有两种用法:1)按位与;2)逻辑与。

&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true 整个表达式的值才是 true。&&之所以称为短路运算,是因为如果&&左边的表达式的值是 false,右边的表达式会被直接短路掉,不会进行运算。

goto 是 Java 中的保留字,在目前版本的 Java 中没有使用。

用于修饰类、属性和方法。

this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。

this的用法在java中大体可以分为3种:

1.普通的直接引用,this相当于是指向当前对象本身。

2.形参与成员名字重名,用this来区分:

3.引用本类的构造函数

super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类。

super也有三种用法:

1.普通的直接引用

与this类似,super相当于是指向当前对象的父类的引用,这样就可以用super.xxx来引用父类的成员。

2.子类中的成员变量或方法与父类中的成员变量或方法同名时,用super进行区分

3.引用父类构造函数

3、引用父类构造函数

static的主要意义是在于创建独立于具体对象的域变量或者方法。以致于即使没有创建对象,也能使用属性和调用方法!

static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。

为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。

1、被static修饰的变量或者方法是独立于该类的任何对象,也就是说,这些变量和方法不属于任何一个实例对象,而是被类的实例对象所共享。

怎么理解 “被类的实例对象所共享” 这句话呢?就是说,一个类的静态成员,它是属于大伙的大伙指的是这个类的多个对象实例,我们都知道一个类可以创建多个实例!,所有的类对象共享的,不像成员变量是自个的自个指的是这个类的单个实例对象我觉得我已经讲的很通俗了,你明白了咩?

2、在该类被第一次加载的时候,就会去加载被static修饰的部分,而且只在类第一次使用时加载并进行初始化,注意这是第一次用就要初始化,后面根据需要是可以再次赋值的。

3、static变量值在类加载的时候分配空间,以后创建类对象的时候不会重新分配。赋值的话,是可以任意赋值的!

4、被static修饰的变量或者方法是优先于对象存在的,也就是说当一个类加载完毕之后,即便没有创建对象,也可以去访问。

因为static是被类的实例对象所共享,因此如果某个成员变量是被所有对象所共享的,那么这个成员变量就应该定义为静态变量。

因此比较常见的static应用场景有:

1、修饰成员变量 2、修饰成员方法 3、静态代码块 4、修饰类【只能修饰内部类也就是静态内部类】 5、静态导包

1、静态只能访问静态。 2、非静态既可以访问非静态的,也可以访问静态的。

break 跳出总上一层循环,不再执行循环(结束当前的循环体)

continue 跳出本次循环,继续执行下次循环(结束正在执行的循环 进入下一个循环条件)

return 程序不再执行下面的代码(结束当前的方法 直接返回)

在Java中,要想跳出多重循环,可以在外面的循环语句前定义一个标号,在里层循环体的代码中使用带有标号的break 语句,即可跳出外层循环。例如:

面向过程:

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

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

面向对象:

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

缺点:性能比面向过程低

面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现。

面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,管我们什么事?我们会用就可以了。

面向对象的底层其实还是面向过程,把面向过程抽象成类,封装,方便我们使用的就是面向对象了。

面向对象的特征主要有以下几个方面:

封装

封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。

继承

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

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

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

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

子类可以用自己的方式实现父类的方法。以后介绍

多态

所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。

在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)

其中Java 面向对象编程三大特性:封装 继承 多态

封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。

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

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

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

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

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

多态性:父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高了程序的拓展性。

在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)

方法重载(overload)实现的是编译时的多态性(也称为前绑定)而方法重写(override)实现的是运行时的多态性(也称为后绑定)

一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:

所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

多态的实现

Java实现多态有三个必要条件:继承、重写、向上转型。

继承:在多态中必须存在有继承关系的子类和父类。

重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。

向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。

只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。

对于Java而言,它多态的实现机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。

抽象类是用来捕捉子类的通用特性的。接口是抽象方法的集合。

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

相同点

不同点

参数抽象类接口

声明抽象类使用abstract关键字声明接口使用interface关键字声明

实现子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现子类使用implements关键字来实现接口。它需要提供接口中所有声明的方法的实现

构造器抽象类可以有构造器接口不能有构造器

访问修饰符抽象类中的方法可以是任意访问修饰符接口方法默认修饰符是public。并且不允许定义为 private 或者 protected

多继承一个类最多只能继承一个抽象类一个类可以实现多个接口

字段声明抽象类的字段声明可以是任意的接口的字段默认都是 static 和 final 的

备注:Java8中接口中引入默认方法和静态方法,以此来减少抽象类和接口之间的差异。

现在,我们可以为接口提供默认实现的方法了,并且不用强制子类来实现它。

接口和抽象类各有优缺点,在接口和抽象类的选择上,必须遵守这样一个原则:

不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类

new关键字,new创建对象实例(对象实例在堆内存中)对象引用指向对象实例(对象引用存放在栈内存中)一个对象引用可以指向0个或1个对象(一根绳子可以不系气球,也可以系一个气球)一个对象可以有n个引用指向它(可以用n条绳子系住一个气球)

变量:在程序执行的过程中,在某个范围内其值可以发生改变的量。从本质上讲,变量其实是内存中的一小块区域

成员变量:方法外部,类内部定义的变量

局部变量:类的方法中的变量。

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

作用域

成员变量:针对整个类有效。 局部变量:只在某个范围内有效。一般指的就是方法,语句体内

存储位置

成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中。 局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。当方法调用完,或者语句结束后,就自动释放。

生命周期

成员变量:随着对象的创建而存在,随着对象的消失而消失 局部变量:当方法调用完,或者语句结束后,就自动释放。

初始值

成员变量:有默认初始值。

局部变量:没有默认初始值,使用前必须赋值。

使用原则

在使用变量时需要遵循的原则为:就近原则 首先在局部范围找,有就使用;接着在成员位置找。

Java程序在执行子类的构造方法之前,如果没有用super来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。

帮助子类做初始化工作。

主要作用是完成对类对象的初始化工作。可以执行。因为一个类即使没有声明构造方法也会有默认的不带参数的构造方法。

名字与类名相同。

没有返回值,但不能用void声明构造函数。

生成类的对象时自动执行,无需调用。

静态变量: 静态变量由于不属于任何实例对象,属于类的,所以在内存中只会有一份,在类的加载过程中,JVM只为静态变量分配一次内存空间。

实例变量: 每次创建对象,都会为每个对象分配成员变量内存空间,实例变量是属于实例对象的,在内存中,创建几次对象,就有几份成员变量。

static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

还有一点就是static成员变量的初始化顺序按照定义的顺序进行初始化。

静态方法和实例方法的区别主要体现在两个方面:

由于静态方法可以不通过对象进行调用,因此在静态方法里,不能调用其他非静态变量,也不可以访问非静态变量成员。

方法的返回值是指我们获取到的某个方法体中的代码执行后产生的结果!前提是该方法可能产生结果返回值的作用:接收出结果,使得它可以用于其他的操作!

在Java中,可以将一个类的定义放在另外一个类的定义内部,这就是内部类。内部类本身就是类的一个属性,与其他属性定义方式一致。

内部类可以分为四种:成员内部类、局部内部类、匿名内部类和静态内部类。

定义在类内部的静态类,就是静态内部类。

静态内部类可以访问外部类所有的静态变量,而不可访问外部类的非静态变量;静态内部类的创建方式,new 外部类.静态内部类,如下:

定义在类内部,成员位置上的非静态类,就是成员内部类。

成员内部类可以访问外部类所有的变量和方法,包括静态和非静态,私有和公有。成员内部类依赖于外部类的实例,它的创建方式外部类实例.new 内部类,如下:

定义在方法中的内部类,就是局部内部类。

定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法中的局部类只能访问外部类的静态变量和方法。局部内部类的创建方式,在对应方法内,new 内部类,如下:

匿名内部类就是没有名字的内部类,日常中使用的比较多。

除了没有名字,匿名内部类还有以下特点:

匿名内部类创建方式:

我们为什么要使用内部类呢?因为它有以下优点:

局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final呢?它内部原理是什么呢?

先看这段代码:

以上例子,为什么要加final呢?是因为生命周期不一致, 局部变量直接存储在栈中,当方法执行结束后,非final的局部变量就被销毁。而局部内部类对局部变量的引用依然存在,如果局部内部类要调用局部变量时,就会出错。加了final,可以确保局部内部类使用的变量与外层的局部变量区分开,解决了这个问题。

运行结果:

构造器不能被继承,因此不能被重写,但可以被重载。

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

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

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

equals : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:

情况1:类没有覆盖 equals 方法。则通过 equals 比较该类的两个对象时,等价于通过“==”比较这两个对象。

情况2:类覆盖了 equals 方法。一般,我们都覆盖 equals 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)

举个例子:

说明:

HashSet如何检查重复

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

hashCode和equals方法的关系

面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?”

hashCode介绍

hashCode 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode函数。

散列表存储的是键值对key-value它的特点是:能根据“键”快速的检索出对应的“值”这其中就利用到了散列码!可以快速找到所需要的对象

为什么要有 hashCode

我们以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode:

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

hashCode与equals的相关规定

如果两个对象相等,则hashcode一定也是相同的

两个对象相等,对两个对象分别调用equals方法都返回true

两个对象有相同的hashcode值,它们也不一定是相等的

因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖

hashCode 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode,则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

是值传递。Java 语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但对对象引用的改变是不会影响到调用者的

Java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,也就是说,方法不能修改传递给它的任何参数变量的内容。

下面通过 3 个例子来给大家说明

结果:

解析:

Java中,2020最新版(图4)

在swap方法中,a、b的值进行交换,并不会影响到 num1、num2。因为,a、b中的值,只是从 num1、num2 的复制过来的。也就是说,a、b相当于num1、num2 的副本,副本的内容无论怎么修改,都不会影响到原件本身。

通过上面例子,我们已经知道了一个方法不能修改一个基本数据类型的参数,而对象引用作为参数就不一样,请看 example2.

结果:

解析:

Java中,2020最新版(图5)

array 被初始化 arr 的拷贝也就是一个对象的引用,也就是说 array 和 arr 指向的时同一个数组对象。 因此,外部对引用对象的改变会反映到所对应的对象上。

通过 example2 我们已经看到,实现一个改变对象参数状态的方法并不是一件难事。理由很简单,方法得到的是对象引用的拷贝,对象引用及其他的拷贝同时引用同一个对象。

很多程序设计语言(特别是,C++和Pascal)提供了两种参数传递的方式:值调用和引用调用。有些程序员(甚至本书的作者)认为Java程序设计语言对对象采用的是引用调用,实际上,这种理解是不对的。由于这种误解具有一定的普遍性,所以下面给出一个反例来详细地阐述一下这个问题。

结果:

解析:

交换之前:

Java中,2020最新版(图6)

交换之后:

Java中,2020最新版(图7)

通过上面两张图可以很清晰的看出: 方法并没有改变存储在变量 s1 和 s2 中的对象引用。swap方法的参数x和y被初始化为两个对象引用的拷贝,这个方法交换的是这两个拷贝

总结

Java程序设计语言对对象采用的不是引用调用,实际上,对象引用是按值传递的。

下面再总结一下Java中方法参数的使用情况:

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

刚开始的时候 JavaAPI 所必需的包是 java 开头的包,javax 当时只是扩展 API 包来说使用。然而随着时间的推移,javax 逐渐的扩展成为 Java API 的组成部分。但是,将扩展从 javax 包移动到 java 包将是太麻烦了,最终会一堆现有的代码。因此,最终决定 javax 包将成为标准API的一部分。

所以,实际上java和javax没有区别。这都是一个名字。

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

Java中,2020最新版(图8)

IO-操作方式分类

Java中,2020最新版(图9)

IO-操作对象分类

简答

详细回答

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

静态编译和动态编译

反射是框架设计的灵魂。

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

举例:①我们在使用JDBC连接数据库时使用Class.forName通过反射加载数据库的驱动程序;②Spring框架也用到很多反射机制,最经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程:1) 将程序内所有 XML 或 Properties 配置文件加载入内存中; 2)Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息; 3)使用反射机制,根据这个字符串获得某个类的Class实例; 4)动态配置实例的属性

1.通过new对象实现反射机制 2.通过路径实现反射机制 3.通过类名实现反射机制

字符串常量池位于堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存储相同的字符串,在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。

不是。Java 中的基本数据类型只有 8 个 :byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type)剩下的都是引用类型(referencetype)Java 5 以后引入的枚举类型也算是一种比较特殊的引用类型。

这是很基础的东西,但是很多初学者却容易忽视,Java 的 8 种基本数据类型中不包括 String,基本数据类型中用来描述文本数据的是 char,但是它只能表示单个字符,比如 ‘a’‘好’ 之类的,如果要描述一段文本,就需要用多个 char 类型的变量,也就是一个 char 类型数组,比如“你好” 就是长度为2的数组 char chars = {‘你’‘好’}

但是使用数组过于麻烦,所以就有了 String,String 底层就是一个 char 类型的数组,只是使用的时候者不需要直接操作底层数组,用更加简便的方式即可完成对字符串的使用。

不变性:String 是只读字符串,是一个典型的 immutable 对象,对它进行任何操作,其实都是创建一个新的对象,再把引用指向该对象。不变模式的主要作用在于当一个对象需要被多线程共享并频繁访问时,可以保证数据的一致性。

常量池优化:String 对象创建之后,会在字符串常量池中进行缓存,如果下次创建同样的对象时,会直接返回缓存的引用。

final:使用 final 来定义 String 类,表示 String 类不能被继承,提高了的安全性。

简单来说就是String类利用了final修饰的char类型数组存储字符,源码如下图所以:

我觉得如果别人问这个问题的话,回答不可变就可以了。 下面只是给大家看两个有代表性的例子:

1 String不可变但不代表引用不可以变

结果:

解析:

2 通过反射是可以修改所谓的“不可变”对象

结果:

解析:

用反射可以访问私有成员, 反射出String对象中的value属性, 进而改变通过获得的value引用改变数组的结构。但是一般我们不会这么做,这里只是简单提一下有这个东西。

String 类是 final 类,不可以被继承。

不一样,因为内存的分配方式不一样。String str=“i”的方式,java 虚拟机会将其分配到常量池中;而 String str=new String“i” 则会被分到堆内存中。

两个对象,一个是静态区的“xyz”一个是用new创建在堆上的对象。

使用 StringBuilder 或者 stringBuffer 的 reverse 方法。

示例代码:

数组没有 length方法 ,有 length 的属性。String 有 length方法。JavaScript中,获得字符串的长度是通过 length 属性得到的,这一点容易和 Java 混淆。

HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。

可变性

String类中使用字符数组保存字符串,private final char value【,所以string对象是不可变的。StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char【 value,这两种对象都是可变的。

线程安全性

String中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。

性能

每次对String 类型进行改变的时候,都会生成一个新的String对象,将指针指向新的String 对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

对于三者使用的总结

如果要操作少量的数据用 = String

单线程操作字符串缓冲区 下操作大量数据 = StringBuilder

多线程操作字符串缓冲区 下操作大量数据 = StringBuffer

装箱:将基本类型用它们对应的引用类型包装起来。

拆箱:将包装类型转换为基本数据类型。

Java 是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java 为每一个基本数据类型都引入了对应的包装类型(wrapper class)int 的包装类就是 Integer,从 Java 5 开始引入了自动装箱/拆箱机制,使得二者可以相互转换。

Java 为每个原始类型提供了包装类型:

原始类型: boolean,char,byte,short,int,long,float,double

包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double

如果整型字面量的值在-128到127之间,那么自动装箱时不会new新的Integer对象,而是直接引用常量池中的Integer对象,超过范围 a1==b1的结果是false

本文相关词条概念解析:

对象

对象原本是一个哲学词语,表示客体事物不以人的意志为转移而又与人的存在相关联的某种规定性。对象从哲学词语变成为一个爱情或与爱情有关的词语,绝对是当代中国人的发明。大约从1950年代开始,由于谈情说爱被视为小资产阶级情调,因而搞对象一词便流行开来,几乎成了谈恋爱的代名词,以其一本正经的事务性和目的性取代了风花雪月的谈恋爱。但它之所以能够大面积地流行开来,恐怕还是与中国人的传统观念和文化心态有关。

网友评论
相关文章
Java调试器,它在所有的实例中的值是一样的

Java调试器,它在所有的实例中的值是一样的

Java调试器,它在所有的实例中的值是一样的[详情]

学了java以后, 我才知道桌球还可以这么玩?

学了java以后, 我才知道桌球还可以这么玩?

学了java以后, 我才知道桌球还可以这么玩?[详情]

德帅下课的可能性就非常大了,哈登和考文顿的暴瘦确实让人怀疑,难道德帅要加强死亡五小的速度,但考文顿也变瘦了

德帅下课的可能性就非常大了,哈登和考文顿的暴瘦确实让人怀疑,难道德帅要加强死亡五小的速度,但考文顿也变瘦了

德帅下课的可能性就非常大了,哈登和考文顿的暴瘦确实让人怀疑,难道德帅要加强死亡五小的速度,但考文顿也变瘦了[详情]

网站地图    Copyright     2016-2018  资讯网   All rights reserved.