Java知识点

2019-01-15  本文已影响0人  wuhuaguo丶


对于基本数据类型来说,他们的按值传递调用函数并不会改变在原函数中的值。

public class Swap {

    public static void main(String[] args) {
        int x = 10;
        int y = 20;
        swap(x, y);
        System.out.println("x(2) = " + x);
        System.out.println("y(2) = " + y);
    }
     public static void swap(int x, int y) {
        int temp = x;
        x = y;
        y = temp;
        System.out.println("x(1) = " + x);
        System.out.println("y(1) = " + y);
    }
}

    /*输出
    x(1) = 20
    y(1) = 10
    x(2) = 10
    y(2) = 20
    */

上面程序main函数调用swap函数来交换 x,y的值,然而调用函数之后发现main中x,y的值并未交换。包括在Java api中找不到一个可以交换两个变量的方法。这与Java语言的特性有关。通过一个图就可以知道上面程序的运行结果了。


由上图可知,main函数中的x,y和swap函数中的x,y分别存放在不同的区域,在main中调用swap函数的时候,会将main中的x,y的值赋给swap中的x,y。当swap函数中对x,y交换时只是对swap帧中的x,y做交换,并不会改变main中的x,y。所以当函数返回时main中的x,y并不会改变。swap执行过程图如下:

对于基本数据类型 short int long float double char byte boolean这八种按值传递调用函数并不会改变在原函数中的值。

引用数据类型的按值传递

引用数据数据类型分为三种:①接口 ②类 ③数组 对于引用数据类型的按值传递先给出一个实例对比实例进行分析。

public static void main(String[] args) {    
        int []a={10,20};
        System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=10,a[1]=20;      
        swap(a, 0, 1);
        System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=20,a[1]=10;  

    }
public static void swap(int []a,int i,int j){
        int temp=a[i];
        a[i]=a[j];
        a[j]=temp;
        System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=20,a[1]=10;
    }
//输出
/*a[0]=10 a[1]=20

  a[0]=20 a[1]=10

  a[0]=20 a[1]=10   
*/

运行程序后发现,swap函数对a[0] ,a[1]的操作竟然影响到了main函数中的a[0] ,a[1]的值,真是不可思议。为什么会产生如此之结果。原来引用类型的按值传递,传递的是对象的地址。还是用图来解释一下。

这里写图片描述
由图可以看出在swap中仅仅是得到了数组的地址,并没有对数组的元素进行复制,在swap中对数组的操作是直接对main函数中数组的操作,因此swap函数返回后main函数中的a[0] ,a[1]的值发生交换。
数组、类、接口按值传递的时候都是传递对象的地址。
public class test1 {
    public static void main(String[] args) {
        String a = new String("ab"); // a 为一个引用
        String b = new String("ab"); // b为另一个引用,对象的内容一样
        String aa = "ab"; // 放在常量池中
        String bb = "ab"; // 从常量池中查找
        if (aa == bb) // true
            System.out.println("aa==bb");
        if (a == b) // false,非同一对象
            System.out.println("a==b");
        if (a.equals(b)) // true
            System.out.println("aEQb");
        if (42 == 42.0) { // true
            System.out.println("true");
        }
    }
}


  1. 修饰成员变量和成员方法
  2. 静态代码块
  3. 修饰类(只能修饰内部类)
  4. 静态导包(用来导入类中的静态资源,1.5之后的新特性)

修饰成员变量和成员方法

被 static 修饰的成员属于类,不属于单个这个类的某个对象,被类中所有对象共享,可以并且建议通过类名调用。被static 声明的成员变量属于静态成员变量,静态变量 存放在 Java 内存区域的方法区。

方法区与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来。

HotSpot 虚拟机中方法区也常被称为 “永久代”,本质上两者并不等价。仅仅是因为 HotSpot 虚拟机设计团队用永久代来实现方法区而已,这样 HotSpot 虚拟机的垃圾收集器就可以像管理 Java 堆一样管理这部分内存了。但是这并不是一个好主意,因为这样更容易遇到内存溢出问题。

调用格式:

类名.静态变量名
类名.静态方法名()
如果变量或者方法被 private 则代表该属性或者该方法只能在类的内部被访问而不能在类的外部被访问。

静态代码块
静态代码块定义在类中方法外, 静态代码块在非静态代码块之前执行(静态代码块—非静态代码块—构造方法)。 该类不管创建多少对象,静态代码块只执行一次.
静态内部类
静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类,但是静态内部类却没有。没有这个引用就意味着:

  1. 它的创建是不需要依赖外围类的创建。
  2. 它不能使用任何外围类的非static成员变量和方法。

静态导包
格式为:import static
这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名调用类中静态成员,可以直接使用类中静态成员变量和成员方法






LinkedList详细介绍(源码解析)和使用示例





  1. int是基本数据类型,Integer是int的包装类
  2. Integer变量必须实例化之后才能使用,而int不需要
  3. Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向这个对象;而int是直接存储数据的值。
  4. Integer默认值是null,int默认值是0.



    for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            if (entry.getValue() > array.length / 2) {
                return entry.getKey();
            }
        }

这种方式既可以获取到key,也可以获取到value
还有其他方法:
foreach中遍历的可以是map.values 仅有values
也可以是map.getKeys 仅有key、
java中Map遍历的四种方式




  1. 为了实现字符串池
  2. 为了线程安全
  3. 为了实现String可以创建HashCode不可变性

首先了解final关键字的用途,它在修饰变量,方法,类时含义各不相同

只有当string是final的,字符串常量池的实现,可以节省内存空间,提高效率(因为不同的字符串变量指向常量池中同一个字符串)
只有当string是final的,同一个字符串实例可以被多个线程共享,这样便不用因为线程安全问题而使用同步。字符串本身便是线程安全的。
只有当String是final的,在它创建的时候hashcode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的key,字符串的处理速度要快过其他键对象,这就是为什么HashMap常常使用String做键的原因。




上一篇 下一篇

猜你喜欢

热点阅读