1. 面向对象编程

Java代码世界由诸多不同功能的类构成,类由以下构成:

  • 属性:类的成员变量
  • 行为:类的成员方法

核心:类的设计!

  1. class person{
  2. // 属性
  3. String name;
  4. int age;
  5. boolean isMarried;
  6. // 方法
  7. pubic void walking(){
  8. System.out.println("walking...")
  9. }
  10. ...
  11. }

2. 可变个数的形参

  • 用数组的方式传递可变参数
  • 用Java特有的…方式传递可变参数,说明
    • 方法参数部分指定类型的参数个数是0到多个
    • 声明方式:方法名(参数的类型名… 参数名)
    • 可变参数方法的使用和数组一样
    • 方法的参数部分有可变形参,需要放在形参声明的最后
  1. public void printInfo (String[] args){
  2. for(String ele: args):
  3. System.out.println(ele);
  4. }
  5. public void printInfo (String... args){
  6. for(String ele: args):
  7. System.out.println(ele);
  8. }

3. 方法的参数传递

  • 形参:形式参数,方法声明时的参数,它用来接收调用者传递来的实参;它只有在被调用时JVM才会为其分配内存单元,调用结束后回收内存单元,因此它的作用域只限于方法内部,对于形参的改变不会影响实参
  • 实参:方法调用时实际传给形参的参数值,实参在传递给其他参数时要先赋值

Java里方法的参数传递只有值传递一种:值传递!即将实际参数值得副本传入方法,而参数本身不受影响。

  • 值传递:如果方法的形参是基本数据类型,那么实参(实际的数据)像形参传递参数时,就是把实参的值复制给了形参
  • 引用传递:如果方法的形参是对象,那么实参(实际的对象)向形参传递参数时也是把值传递给形参,而这个值是实参在栈内存中的值,这个值也是引用对象在堆内存种的地址

那么什么时候是值传递,什么时候是引用传递呢?顾名思义,当实参为Java中的八种基本数据类型时,在调用方法传递实参时就是值传递;当实参是除了八种基本类型之外的对象时,调用方法时就是引用传递,即传递给被调用方法的时对象在堆内存的地址。

  • 基本数据类型(八种):整数类型(byte, short, int, long)、浮点类型(float, double)、字符类型(char)、boolean类型(true, false)
  • long型变量赋值时后面要在值后面跟上字母 l
  • float型变量赋值时要在值后面跟上字母 f
  • byte、int、long、和short都可以用十进制、16进制以及8进制的方式来表示。当使用常量的时候,前缀 0 表示 8 进制,而前缀 0x 代表 16 进制
  1. package com.company;
  2. public class Main {
  3. public static void main(String[] args) {
  4. // byte
  5. System.out.println("基本类型:byte 二进制位数:" + Byte.SIZE);
  6. System.out.println("包装类:java.lang.Byte");
  7. System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE);
  8. System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE);
  9. System.out.println();
  10. // short
  11. System.out.println("基本类型:short 二进制位数:" + Short.SIZE);
  12. System.out.println("包装类:java.lang.Short");
  13. System.out.println("最小值:Short.MIN_VALUE=" + Short.MIN_VALUE);
  14. System.out.println("最大值:Short.MAX_VALUE=" + Short.MAX_VALUE);
  15. System.out.println();
  16. // int
  17. System.out.println("基本类型:int 二进制位数:" + Integer.SIZE);
  18. System.out.println("包装类:java.lang.Integer");
  19. System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE);
  20. System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE);
  21. System.out.println();
  22. // long
  23. System.out.println("基本类型:long 二进制位数:" + Long.SIZE);
  24. System.out.println("包装类:java.lang.Long");
  25. System.out.println("最小值:Long.MIN_VALUE=" + Long.MIN_VALUE);
  26. System.out.println("最大值:Long.MAX_VALUE=" + Long.MAX_VALUE);
  27. System.out.println();
  28. // float
  29. System.out.println("基本类型:float 二进制位数:" + Float.SIZE);
  30. System.out.println("包装类:java.lang.Float");
  31. System.out.println("最小值:Float.MIN_VALUE=" + Float.MIN_VALUE);
  32. System.out.println("最大值:Float.MAX_VALUE=" + Float.MAX_VALUE);
  33. System.out.println();
  34. // double
  35. System.out.println("基本类型:double 二进制位数:" + Double.SIZE);
  36. System.out.println("包装类:java.lang.Double");
  37. System.out.println("最小值:Double.MIN_VALUE=" + Double.MIN_VALUE);
  38. System.out.println("最大值:Double.MAX_VALUE=" + Double.MAX_VALUE);
  39. System.out.println();
  40. // char
  41. System.out.println("基本类型:char 二进制位数:" + Character.SIZE);
  42. System.out.println("包装类:java.lang.Character");
  43. // 以数值形式而不是字符形式将Character.MIN_VALUE输出到控制台
  44. System.out.println("最小值:Character.MIN_VALUE="
  45. + (int) Character.MIN_VALUE);
  46. // 以数值形式而不是字符形式将Character.MAX_VALUE输出到控制台
  47. System.out.println("最大值:Character.MAX_VALUE="
  48. + (int) Character.MAX_VALUE);
  49. }
  50. }
  51. /*
  52. 基本类型:byte 二进制位数:8
  53. 包装类:java.lang.Byte
  54. 最小值:Byte.MIN_VALUE=-128
  55. 最大值:Byte.MAX_VALUE=127
  56. 基本类型:short 二进制位数:16
  57. 包装类:java.lang.Short
  58. 最小值:Short.MIN_VALUE=-32768
  59. 最大值:Short.MAX_VALUE=32767
  60. 基本类型:int 二进制位数:32
  61. 包装类:java.lang.Integer
  62. 最小值:Integer.MIN_VALUE=-2147483648
  63. 最大值:Integer.MAX_VALUE=2147483647
  64. 基本类型:long 二进制位数:64
  65. 包装类:java.lang.Long
  66. 最小值:Long.MIN_VALUE=-9223372036854775808
  67. 最大值:Long.MAX_VALUE=9223372036854775807
  68. 基本类型:float 二进制位数:32
  69. 包装类:java.lang.Float
  70. 最小值:Float.MIN_VALUE=1.4E-45
  71. 最大值:Float.MAX_VALUE=3.4028235E38
  72. 基本类型:double 二进制位数:64
  73. 包装类:java.lang.Double
  74. 最小值:Double.MIN_VALUE=4.9E-324
  75. 最大值:Double.MAX_VALUE=1.7976931348623157E308
  76. 基本类型:char 二进制位数:16
  77. 包装类:java.lang.Character
  78. 最小值:Character.MIN_VALUE=0
  79. 最大值:Character.MAX_VALUE=65535
  80. */
  • 引用数据类型:除了八种基本数据类型之外的都是引用类型
    • String:由0或多个字母数字符号组成的串;可由null初始化;值不可变

JVM的内存需要划分为5个部分:

  • 栈(Stack):存放的是方法中的局部变量
    • 局部变量:方法的参数或是是方法{}内部的变量
    • 作用域:一旦超出作用域,立刻从栈内存中消失
  • 堆(Heap):凡是new出来的东西都在堆中,堆内存的里面的东西都有一个16进制地址;堆内存里面的数据都有默认值:
    • 整形:0
    • 浮点型:0.0
    • 字符:“\u0000”
    • 布尔:false
    • 引用类型:null
  • 方法区(Method Area):存储.class相关信息,包含方法的信息
  • 本地方法栈(Native Method Stack):与OS有关
  • 寄存器(pc Register):与CPU有关

JVM内存的简要示意图如下所示:
image-20200417101436408.png

值传递:

  1. public class argsTest {
  2. public static void main(String[] args) {
  3. int a = 1;
  4. int b = 2;
  5. System.out.println("没有交换前:" + "a = " + a + ",b = " + b);
  6. swapNumbers(a, b);
  7. System.out.println("交换后:" + "a = " + a + ",b = " + b);
  8. }
  9. private static void swapNumbers(int a, int b) {
  10. int temp = a;
  11. a = b;
  12. b = temp;
  13. System.out.println("交换中:" + "a = " + a + ",b = " + b);
  14. }
  15. }
  16. /**
  17. * 没有交换前:a = 1,b = 2
  18. * 交换中:a = 2,b = 1
  19. * 交换后:a = 1,b = 2
  20. */

image-20200417103412600.png
如上图所示,当在main()中初始化a,b时,由于它们属于基本数据类型,因此JVM会为a和b在栈中分配内存空间用于存放初始化的值。而当在调用swapNumbers(int a, int b)方法时,main()中swapNumbers(a, b)中的a和b是最初a和b的副本,JVM会为它们另外开辟空间存放,由于它们在栈中存放的地址不同,因此被调用方法内对于a和b的改变不影响最初的值。

引用传递:

  1. package com.company;
  2. class Data{
  3. int a = 1;
  4. int b = 2;
  5. }
  6. public class argsTest {
  7. public static void main(String[] args) {
  8. Data d = new Data();
  9. System.out.println("没有交换前:" + "a = " + d.a + ",b = " + d.b);
  10. swapNumbers(d);
  11. System.out.println("交换后:" + "a = " + d.a + ",b = " + d.b);
  12. }
  13. private static void swapNumbers(Data d) {
  14. int temp = d.a;
  15. d.a = d.b;
  16. d.b = temp;
  17. System.out.println("交换中:" + "a = " + d.a + ",b = " + d.b);
  18. }
  19. }
  20. /**
  21. * 没有交换前:a = 1,b = 2
  22. * 交换中:a = 2,b = 1
  23. * 交换后:a = 2,b = 1
  24. */

而当我们传递给swapNumbers()的是一个类对象时,实际传递的是该引用对象在堆中的地址。swapNumbers()中的对象和main()中的对象保存的都是相同的内容,即所指向的引用对象在堆中的地址。因此,swapNumbers()中对于对象的改变实际上直接改变了堆中的对象,那么main()中的对象的值自然也就发生了改变。

如下所示,当执行Data d = new Data()时,JVM首先会在堆中开辟空间存放创建的new Data(),然后在栈中为d开辟空间存放new Data()的地址,即d的值。然后当执行swapNumbers()时,JVM首先为其在栈中开辟空间存放传入的对象在堆中的地址,然后执行下面的流程。因此,它们指向的是堆中同样的对象,swapNumbers()中对于对象的改变也会影响main()中d对应的值。
image-20200417104209851.png