JAVAbase

JAVABASE

基础知识

JAVA语言优点

面对对象,平台无关(JAVA平台无关,JVM平台有关),内存管理,安全性,多线程,JAVA是解释型的

Java 和 C++的区别
  1. 多重继承(java接口多重,类不支持,C++支持)
  2. 自动内存管理
  3. 预处理功能
  4. goto语句(java不支持)
  5. 引用与指针。在Java中不可能直接操作对象本身,所有的对象都由一个引用指向,必须通过这个引用才能访问对象本身,包括获取成员变量的值,改变对象的成员变量,调用对象的方法等。而在C++中存在引用,对象和指针三个东西,这三个东西都可以访问对象。其实,Java中的引用和C++中的指针在概念上是相似的,他们都是存放的对象在内存中的地址值,只是在Java中,引用丧失了部分灵活性,比如Java中的引用不能像C++中的指针那样进行加减运算
JDK 包.

JDK 常用的 package:

  • java.lang:这个是系统的基础类,比如 String 等都是这里面的,这个 package 是唯一一个可以不用 import 就可以使用的 Package
  • java.io: 这里面是所有输入输出有关的类,比如文件操作等
  • java.net: 这里面是与网络有关的类,比如 URL,URLConnection 等。
  • java.util: 这个是系统辅助类,特别是集合类 Collection,List,Map 等。
  • java.sql: 这个是数据库操作的类,Connection, Statememt,ResultSet 等
JDK, JRE 和 JVM 的区别

JDK,JRE和JVM 是 Java 编程语言的核心概念。尽管它们看起来差不多,作为程序员我们也不怎么关心这些概念,但是它们是不同的针对特定目的的产品。这是一道常见的 Java 面试题,而本文则会一一解释这些概念并给出它们之间的区别。

1)Java 开发工具包 (JDK)

Java 开发工具包是 Java 环境的核心组件,并提供编译、调试和运行一个 Java 程序所需的所有工具,可执行文件和二进制文件。包括java基础jar包、虚拟机、javac等可执行文件等。JDK 是一个平台特定的软件,有针对 Windows,Mac 和 Unix 系统的不同的安装包。可以说 JDK 是 JRE 的超集,它包含了 JRE 的 Java 编译器,调试器和核心类。

2)Java 虚拟机(JVM)

JVM 是 Java 编程语言的核心。当我们运行一个程序时,JVM 负责将字节码转换为特定机器代码。JVM 也是平台特定的,并提供核心的 Java 方法,例如内存管理、垃圾回收和安全机制等。JVM 是可定制化的,我们可以通过 Java 选项(java options)定制它,比如配置 JVM 内存的上下界。JVM 之所以被称为虚拟的是因为它提供了一个不依赖于底层操作系统和机器硬件的接口。这种独立于硬件和操作系统的特性正是 Java 程序可以一次编写多处执行的原因。

3)Java 运行时环境(JRE)

JRE 是 JVM 的实施实现,它提供了运行 Java 程序的平台。JRE 包含了 JVM、Java 二进制文件和其它成功执行程序的类文件。JRE 不包含任何像 Java 编译器、调试器之类的开发工具。如果你只是想要执行 Java 程序,你只需安装 JRE 即可,没有安装 JDK 的必要。

JDK, JRE 和 JVM 的区别

  • JDK 是用于开发的而 JRE 是用于运行 Java 程序的。
  • JDK 和 JRE 都包含了 JVM,从而使得我们可以运行 Java 程序。
  • JVM 是 Java 编程语言的核心并且具有平台独立性。
  • JDK》JRE》JVM 包含关系。

即时编译器(JIT)

JIT 是 JVM 的一部分,它可以在同一时间编译类似的字节码来优化将字节码转换为机器特定语言的过程相似的字节码,从而将优化字节码转换为机器特定语言的过程,这样减少转换过程所需要花费的时间。

主方法中args是什么意思

String[] args:是保存运行main函数时输入的参数的字符串数组,当在CMD运行时,输入:java test a b c ,数组就会将abc 保存起来:args[0]=a; args[2]=b; args[3]=c;这些变量是可以调用的。

值传递和引用传递
java值传递问题
  1. 对象就是传引用
  2. 原始类型就是传值
  3. String,Integer, Double等immutable类型因为没有提供自身修改的函数,每次操作都是新生成一个对象,所以要特殊对待。可以认为是传值。

Integer 和 String 一样。保存value的类变量是Final属性,无法被修改,只能被重新赋值/生成新的对象。 当Integer 做为方法参数传递进方法内时,对其的赋值都会导致 原Integer 的引用被 指向了方法内的栈地址,失去了对原类变量地址的指向。对赋值后的Integer对象做得任何操作,都不会影响原来对象。

  • 变量被值传递,意味着传递了变量的一个副本。因此,就算是改变了变量副本,也不会影响源对象的值。

  • 对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对象所做的改变会反映到所有的对象上。
    java本质上还是值传递,如方法调用的时候传入一个对象引用进去,在方法栈中会构建一个副本和该引用变量值相同指向同一个地址。如果改变引用的值不会对改变传入的引用的值。

静态变量和实例变量的区别
  • 在语法定义上的区别:静态变量前要加 static 关键字,而实例变量前则不加。
    类变量是所有对象共有,其中一个对象将它值改变,其他对象得到的就是改变后的结果;而实例变量则属对象私有,某一个对象将其值改变,不影响其他对象。
  • 所有的实例对象都共用一个类变量,内存中只有一处空间是放这个类变量值的。因此,如果一个对象把类变量值改了,另外一个对象再取类变量值就是改过之后的了。在创建实例对象的时候,内存中会为每一个实例对象的每一个非静态成员变量开辟一段内存空间,用来存储这个对象所有的非静态成员变量值,即使两个不同的实例对象是属于同一个 class 类,但是它们的同名非静态成员变量在内存中占用的空间是不同的。
  • 在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
是否可以在 static 环境中访问非 static 变量
  • static 变量在 Java 中是属于类的,它在所有的实例中的值是一样的。当类被Java虚拟机载入的时候,会对 static 变量进行初始化。如果你的代码尝试不用实例来访问非 static 的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。
  • 在非静态方法中(非main)方法,可以直接调用本类非静态方法,因为,此时不涉及累的加载。
源码、反码、补码

0(符号位,正为0,一般省略)101010010011,正数一般源码,反码,补码不变

11010101001 (开头的1是符号位)反码 除符号位之外,其他的按位取反。补码 ,在反码的基础上+1。

JAVA 基本数据类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vUkmZv1N-1617721577871)(D:\001desktop\笔记\java整理\image-20210331160734583.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SU3UWyO5-1617721577873)(D:\001desktop\笔记\java整理\image-20210331160843434.png)]

基本数据类型强制转换

基本类型的强制转换主要是包括隐式强转,和显示强转,隐式强转是自动转换,显示强转是手动转换,一般显示强转是因为类型自动隐式强转,如果不手动强转是会出现错误。

  1. ①byte b=4;b=b+1;//错误,因为右侧变成了 int 型 , 1 是 int 型,占四个八位,b 是 byte 型,占 1个八位,他们相加,需要 4 个八位空间才能容纳下其和,所以,右侧隐式强转为 int 型,然而左侧是 byte 型,装不下,所以会报错。

  2. ②b=(char)(b+1);//正确,这个就是显示强转,我们手动把本来是 int 类型的类型转化为和左侧相同的 char 型已规避错误;

  3. ③b+=1;//正确,因为这个提前要进行一次判断,就是 1 是不是在 byte 范围内,结果是,所以就把 1 当做 byte 型,赋给左边。

  4. ④byte a=3,b=4,c;c=a+b;//错误,两个 byte 型相加,不应该还是 byte 类型?这是因为在 java 中,两个 byte相加,为了防止再放到 byte 中溢出,所以将其强转为 int 型,这里的强转是隐式的,然而左边是 byte 类型数据,所以会报错。

  5. ⑤c=3+4;//正确, 原因是,右侧的和是 7,然后他就会判断,7 是不是在 byte 数据类型的范围内,结果是,所以就把 7 当做是 byte 类型,直接赋值给左边。所以正确。

  6. ⑥int a; byte b=3,e - 17 - short s=3,t;e=s+b;//错误t=s+b;//错误a=s+b;//正确 这个例子得出一个结论就是,byte 类型数据,和别的类型的数据也是会转化为 int 类型。为什么一个 byte 类型,和一个 short 类型会转化为 int 类型,一个占 1 个八位,一个占 4 个八位,不是应该相加后转化为 short 类型? 原因是当两个数相加后防止溢出,所以就转为 int,而 short 就放不下。

  7. ⑦byte b=3,e;

    float f=3f;

    double d=3;

    f=b+f;//正确。

    d=b+d;//正确。这两个和 byte 和 int 相加一样,都是隐式强转为所占空间更大的哪一个数据类型。所以可以得出一个结论就是 byte 和别的数据类型的数据相加,如果另一个数据的数据类型<int 类型,也就是 short ,byte 小于 4 个八位的数,那么他就会隐式强转为 int 类型,而和别的相加就会隐式转化为更高位的数据类型。隐式数据转换

  • byte,short,char—>int —>long —>float—>double 即小范围的类型可以

  • boolean型不能和其他类型转换

  • byte,short和 char类型不能相互转换,它们参 与运算的时候,系统会先自动转换成ASCII码表对应 的int类型的数值,即使是同一个数据类型的计算,如 两个char,两个short相加

  • 整数和浮点数在计算机中的表示方式不同,所以float的表示范围实际比 long更大

    float的范围: 3.403 * 10^38 > 2* 2^114 > 2^63 - 1; long的范围: 2^63 -1

char 型变量

char 类型可以存储一个中文汉字,因为 Java 中使用的编码是** Unicode**(不选择任何特定的编码,直接使用字符在字符集中的编号,这是统一的唯一方法),一个 char 类型占 2 个字节(16bit),所以放一个中文是没问题的。

补充:使用 Unicode 意味着字符在 JVM 内部和外部有不同的表现形式,在 JVM 内部都是 Unicode,当这个字符被从 JVM 内部转移到外部时(例如存入文件系统中),需要进行编码转换。所以 Java 中有字节流和字符流,以及在字符流和字节流之间进行转换的转换流,如 InputStreamReader 和 OutputStreamReader.

&和&&
  • &&具有短路功能,即第一个表达式为false时,就不在进行第二个表达式的运算
  • &两边的操作符不是Boolean类型的时,进行与操作
Java 中的 final关键字用法
  • (1)修饰类:表示该类不能被继承;
  • (2)修饰方法:表示方法不能被覆盖;
  • (3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。
final, finally, finalize 的区别?
  • final:修饰符(关键字)有三种用法:如果一个类被声明为final,意味着它不能再派生出新的子类,即不能被继承,因此它和 abstract 是反义词。将变量声明为 final,可以保证它们在使用中不被改变,被声明为 final 的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改。被声明为 final 的方法也同样只能使用,不能在子类中被重写。

  • finally:通常放在 try…catch 的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要 JVM 不关闭都能执行,可以将释放外部资源的代码写在 finally 块中。

  • finalize:Object 类中定义的方法,Java 中允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize() 方法可以整理系统资源或者执行其他清理工作。

assert(???------------???)

assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。一般来说,assertion 用于保证程序最基本、关键的正确性。assertion 检查通常在开发和测试时开启。为了提高性能,在软件发布后, assertion 检查通常是关闭的。在实现中,断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为 true;如果表达式计算为 false,那么系统会报告一个 AssertionError。

断言用于调试目的:

	assert(a > 0); // throws an AssertionError if a <= 0

断言可以有两种形式:

	assert Expression1;
	assert Expression1 : Expression2 ;

Expression1 应该总是产生一个布尔值。
Expression2 可以是得出一个值的任意表达式;这个值用于生成显示更多调试信息的字符串消息
断言在默认情况下是禁用的,要在编译时启用断言,需使用 source 1.4 标记:

	javac -source 1.4 Test.java

要在运行时启用断言,可使用 -enableassertions 或者 -ea 标记。
要在运行时选择禁用断言,可使用 -da 或者 -disableassertions 标记。

equals与==的区别
  1. == 是一个运算符。
  2. Equals则是string对象的方法,可以.(点)出来。
    我们比较无非就是这两种 1、基本数据类型比较 2、引用对象比较

1、基本数据类型比较
 ==比较两个值是否相等。相等为true 否则为false;
equals不能直接用于基本类型的比较。需要将基本类型转换为包装器进行比较。

2、引用对象比较
==和equals都是比较栈内存中的地址是否相等 。相等为true 否则为false;  
需注意几点:

1、string是一个特殊的引用类型。对于两个字符串的比较,不管是 == 和 equals 这两者比较的都是字符串是否相同;

2、当你创建两个string对象时,内存中的地址是不相同的,你可以赋相同的值。
  所以字符串的内容相同。引用地址不一定相同,(相同内容的对象地址不一定相同),但反过来却是肯定的;

3、基本数据类型比较(string 除外) == 和 Equals 两者都是比较值;

  • 和 equals 都是比较的,而前者是运算符,后者则是一个方法,基本数据类型和引用数据类型都可以使用运算符,而只有引用类型数据才可以使用 equals,下面具体介绍一下两者的用法以及区别.

  • 操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用操作符。如果一个变量指向的数据是对象类型的,那么,这时候涉及了两块内存,对象本身占用一块内存(堆内存),变量也占用一块内存,例如 Objet obj = new Object();变量 obj 是一个内存,new Object()是另一个内存,此时,变量 obj 所对应的内存中存储的数值就 是对象占用的那块内存的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向 同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作 符进行比较。 equals 方法是用于比较两个独立对象的内容是否相同,就好比去比较两个人的长相是 否相同,它比较的两个对象是独立的。

String、StringBuffer与StringBuilder的区别

  1. String是字符串常量,是不可变类。如果要操作少量的数据用
  2. StringBuffer是字符串变量,是线程安全的。多线程操作字符串缓冲区 下操作大量数据
  3. StringBuilder是字符串变量,非线程安全。单线程操作字符串缓冲区 下操作大量数据

速度:StringBuilder > StringBuffer > String

String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:

String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“simple”).append(“ test”);
  • Java 平台提供了两种类型的字符串:String 和StringBuffer / StringBuilder,它们可以储存和操作字符串。其中 String 是只读字符串,也就意味着 String 引用的字符串内容是不能被改变的。

  • 而 StringBuffer 和 StringBuilder 类表示的字符串对象可以直接进行修改。StringBuilder 是 JDK 1.5 中引入的,它和 StringBuffer 的方法完全相同,区别在于它是在单线程环境下使用的,因为它的所有方面都没有被 synchronized 修饰,因此它的效率也比 StringBuffer 略高。

  • 有一个面试题问:有没有哪种情况用 + 做字符串连接比调用 StringBuffer / StringBuilder 对象的 append 方法性能更好?如果连接后得到的字符串在静态存储区中是早已存在的,那么用+做字符串连接是优于 StringBuffer / StringBuilder 的 append 方法的。

String不可变性

至于为什么要把 String 类设计成不可变类,是它的用途决定的。其实不只 String,很多 Java 标准类库中的类都是不可变的。在开发一个系统的时候,我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优点,比如因为它的对象是只读的,所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如每个不同的状态都要一个对象来代表,可能会造成性能上的问题。所以 Java 标准类库还提供了一个可变版本,即 StringBuffer。

Javac 编译可以对字符串常量直接相加的表达式进行优化,不必要等到运行期去进行加法运算处理,而是在编译时去掉其中的加号,直接将其编译成一个这些常量相连的结果。所以 String s=“a”+”b”+”c”+”d”;只生成一个对象.

为什么String要设计成不可变的**

在Java中将String设计成不可变的是综合考虑到各种因素的结果,如内存,同步,数据结构以及安全等方面的考虑.

  1. 字符串常量池的需要.
    字符串池的实现可以在运行时节约很多heap空间,因为不同的字符串变量都指向池中的同一个字符串。但如果字符串是可变的,那么String interning将不能实现(译者注:String interning是指对不同的字符串仅仅只保存一个,即不会保存多个相同的字符串。),因为这样的话,如果变量改变了它的值,那么其它指向这个值的变量的值也会一起改变。
  2. 线程安全考虑。
    同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。
  3. 类加载器要用到字符串,不可变性提供了安全性,以便正确的类被加载。譬如你想加载java.sql.Connection类,而这个值被改成了myhacked.Connection,那么会对你的数据库造成不可知的破坏。
  4. 支持hash映射和缓存。
    因为字符串是不可变的,所以在它创建的时候hashcode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串。

对象

Object有哪些公用方法
  • protected Object clone()创建并返回此对象的一个副本。
  • public boolean equals(Object obj)指示其他某个对象是否与此对象“相等”。
  • protected void finalize()当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
  • public final native Class< ? > getClass() 返回此 Object 的运行时类。
  • public int hashCode()返回该对象的哈希码值。
  • public String toString()返回该对象的字符串表示。
  • public void notify()唤醒在此对象监视器上等待的单个线程。
  • public void notifyAll()唤醒在此对象监视器上等待的所有线程。
  • public void wait()在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
  • public void wait(long timeout)在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
  • public void wait(long timeout, int nanos)在其他线程调用此对象的 notify() 方法或

注意:

  1. 如果一个类实现了Cloneable,Object的clone方法就返回该对象的逐域拷贝,否则就会抛出CloneNotSupportException异常。java.lang.Cloneable 是一个标示性接口,不包含任何方法(详见《effective java》 p46)。

  2. 覆盖equals()时总要覆盖hashCode()(详见《effective java》p39)
    在每个覆盖equals方法的类中也必须覆盖hashCode方法,如果不这样做就会导致Object.hashCode的通用约定—相等的对象必须具有相等的散列码的约定,从而导致该类无法集合所有基于散列集合一起工作,这样的集合有HashMap,HashSet和HashTable。HashMap等使用Key对象的hashCode()和equals()方法去决定key-value对的索引。如果将equals相等的对象认为是同一个对象的话,那么put方法将对象放在一个散列桶,而get方法可能从另一个散列桶获取该对象,因为这两个方法传入的对象虽然equals相同,但hashCode可能不同,而hashMap根据hashCode去定位散列桶位置导致出现在不同的散列桶中。

Hashcode的作用。

  1. hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的;
  2. 比较对象是否相同。

一下是关于hashCode的约定:
1、如果两个对象相同,就是适用于equals(java.lang.Object) 方法,那么这两个对象的hashCode一定要相同;

2、如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面提到的第2点;

3、两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子里”。

创建对象时,内存问题

class test{} main{ test t = new test(); } ①开辟了栈内存空间,有一个变量 t,存放堆内存地址 new test(); ②class test{}; 中包含一个空的构造方法,以及其从 Object 类中继承的所有东西,会分配 内存。如果对 new 出来的东西一直没有释放掉对它的引用,java 的垃圾收集机制无法对其 进行回收的,当创建的对象足够多时,会内存溢出。

不可变对象

如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的。不能改变状态的意思是,不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,引用类型指向的对象的状态也不能改变。
如何创建不可变类

  1. 将类声明为final,所以它不能被继承
  2. 将所有的成员声明为私有的,这样就不允许直接访问这些成员
  3. 对变量不要提供setter方法
  4. 将所有可变的成员声明为final,这样只能对它们赋值一次
  5. 通过构造器初始化所有成员,进行深拷贝(deep copy):如果某一个类成员不是原始变量(primitive)或者不可变类,必须通过在成员初始化(in)或者get方法(out)时通过深度clone方法,来确保类的不可变。
  6. 在getter方法中,不要直接返回对象本身,而是克隆对象,并返回对象的拷贝
序列化

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。

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

Java 对象实现序列化要实现 Serializable 接口。

  • 反序列化并不会调用构造方法。反序列的对象是由 JVM 自己生成的对象,不通过构造方法生成。
  • 序列化对象的引用类型成员变量,也必须是可序列化的,否则,会报错。
  • 如果想让某个变量不被序列化,使用 transient 修饰。
  • 单例类序列化,需要重写 readResolve() 方法。

其他

可变参数为什么要定义在参数列表的后面
  • void add(int a ) void add(int a, int b) void add (int a,int b,int c) 比如这里的 add 方法就是向集合中添加元素的方法,我们发现这样的重载会使得代码 很臃肿,而且复用性也不是很高。 在之前的 java 版本中是这样设计的:void add(int[] a),就是将接受到的参数类型 变成一个数组,在方法中对数组进行遍历,这样数组中有几个元素,就添加几个元素,从而 就简化了程序。

  • 后来出现了可变参数了,就可以将上边的代码写为:public void add(int …is){},虽然形式上发生了改变,但其内部的调用方式是没有变化的,也就是将接 受来个数不确定的参数,装在一个数组中,而且从 int…开始后所有的参数,就会作为数组 中的元素装进数组中。当然有的时候,参数中包含其他参数和可变参数,比如:public void add(String a,int …is){}:那么从 int…开始之后的参数就是可变参数,而 a 这个参数就不装 入到数组中了。那么,如果写成 public void add(int …is,String a){} :根据调用的规则, a 也会作为一个参数添加到数组中去,这当然与我们的程序设计初衷是不相符的。所以,在 使用可变参数的时候,要将可变参数定义在参数列表的最后面。

堆内存与栈内存的区别
  • ①heep (堆)是一个可动态申请的内存空间,一般所有创建的对象都放在这里。 stack (栈)是一个先进后出的数据结构,通常用于保存方法(函数)中的参数,局部变量。 stack (栈)的空间小,但速度比较快, 存放对象的引用,通过栈中的地址索引可以找到 堆中的对象。
  • ②栈(java stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是 java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈用于存储局部变量表、操 作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个 栈帧在虚拟机栈中从入栈到出栈的过程。 堆(java Heap)是 java 虚拟机所管理的内存中最大的一块。Java 堆是被所有线程共享的 一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有 的对象实例都在这里分配内存。
变量不赋值与赋 null 的区别
  • 在内存中只有赋值了才初始化变量,全局变量自动赋予初始值,局部变量必须手动赋 值 ,最好全部都手动赋值,自动赋值赋的也是 0 或者 null。内存空间如果赋值 null ,就是 进行了初始化。
    1. Java 中 4 个系统定义的常量:NaN 非数值、lnf 无穷大、-lnf 负无穷大、null 空。
    2. null 用来标识一个不确定的对象,可以赋给引用型变量,不可以赋给基本类型变量
      eap)是 java 虚拟机所管理的内存中最大的一块。Java 堆是被所有线程共享的 一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有 的对象实例都在这里分配内存。
变量不赋值与赋 null 的区别
  • 在内存中只有赋值了才初始化变量,全局变量自动赋予初始值,局部变量必须手动赋 值 ,最好全部都手动赋值,自动赋值赋的也是 0 或者 null。内存空间如果赋值 null ,就是 进行了初始化。
    1. Java 中 4 个系统定义的常量:NaN 非数值、lnf 无穷大、-lnf 负无穷大、null 空。
    2. null 用来标识一个不确定的对象,可以赋给引用型变量,不可以赋给基本类型变量
    3. Object 是已知的存在所有类的超类,但不包含不存在的类,也不包含 null。基本数据类型不 是类不包含在 Object 中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王不二kkw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值