java知识点杂货铺【三】

本文深入讲解Java中的关键字native、strictfp、volatile、synchronized的作用及用法,介绍基本数据类型与引用数据类型的差别,探讨值传递、引用传递、副本传递的区别,并提供了快速排序算法的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、java一些关键字的含义与举例

1、native:此关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。
 Java不是完美的,Java的不足除了体现在运行速度上要比传统的C++慢许多之外,Java无法直接访问到操作系统底层(如系统硬件等),为此Java使用native方法来扩展Java程序的功能。
  可以将native方法比作Java程序同C程序的接口,其实现步骤:
  1、在Java中声明native()方法,然后编译。
  2、用javah产生一个.h文件。
  3、写一个.cpp文件实现native导出方法,其中需要包含第二步产生的.h文件(注意其中又包含了JDK带的jni.h文件)。
  4、将第三步的.cpp文件编译成动态链接库文件。
  5、在Java中用System.loadLibrary()方法加载第四步产生的动态链接库文件,这个native()方法就可以在Java中被访问了。
  JAVA的native方法适用的情况:
  1、为了使用底层的主机平台的某个特性,而这个特性不能通过JAVA API访问。
  2、为了访问一个老的系统或者使用一个已有的库,而这个系统或这个库不是用JAVA编写的。
  3、为了加快程序的性能,而将一段时间敏感的代码作为本地方法实现。
  链接:为什么要用Java native
  java native代码举例:
  

public interface TestInterface {    
     void doMethod();    
}    
public class Test implements TestInterface {    
    public native void doMethod();    
    private native int doMethodB();    
  public native synchronized String doMethodC();    
  static native void doMethodD();    
}    

2、strictfp:本关键字可应用于类、接口或方法。使用 strictfp 关键字声明一个方法时,该方法中所有的float和double表达式都严格遵守FP-strict的限制,符合IEEE-754规范。当对一个类或接口使用 strictfp 关键字时,该类中的所有代码,包括嵌套类型中的初始设定值和代码,都将严格地进行计算。严格约束意味着所有表达式的结果都必须是 IEEE 754 算法对操作数预期的结果,以单精度和双精度格式表示。
  如果你想让你的浮点运算更加精确,而且不会因为不同的硬件平台所执行的结果不一致的话,可以用关键字strictfp.
示例 1
  下面的示例演示了一个使用 strictfp 修饰符声明的类:
  

public strictfp class MyClass {   
    public static void main(String[] args)   
    {   
        float aFloat = 0.6710339f;   
        double aDouble = 0.04150553411984792d;   
        double sum = aFloat + aDouble;   
        float quotient = (float)(aFloat / aDouble);   
        System.out.println("float: " + aFloat);   
        System.out.println("double: " + aDouble);   
        System.out.println("sum: " + sum);   
        System.out.println("quotient: " + quotient);   
    }   
} 

// Example of precision control with strictfp
public strictfp class MyClass {
  public static void main(String[] args)
  {
    float aFloat = 0.6710339f;
    double aDouble = 0.04150553411984792d;
    double sum = aFloat + aDouble;
    float quotient = (float)(aFloat / aDouble);
    System.out.println("float: " + aFloat);
    System.out.println("double: " + aDouble);
    System.out.println("sum: " + sum);
    System.out.println("quotient: " + quotient);
  }
}

运行结果:
float: 0.6710339
double: 0.04150553411984792
sum: 0.7125394529774224
quotient: 16.167336

3、 Volatile :Java 语言提供了一种稍弱的同步机制,即 volatile 变量.用来确保将变量的更新操作通知到其他线程,保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新. 当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的.
参考链接:
Java并发编程:volatile关键字解析
java中volatile关键字的含义

4、Synchroize:多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题。同步机制可以使用synchronized关键字实现。
当synchronized关键字修饰一个方法的时候,该方法叫做同步方法。
当synchronized方法执行完或发生异常时,会自动释放锁。
它修饰的对象有以下几种:
1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

/**
 * synchronized的用法举例:
 * 同步线程
 */
class SyncThread implements Runnable {
   private static int count;

   public SyncThread() {
      count = 0;
   }

   public  void run() {
      synchronized(this) {
         for (int i = 0; i < 5; i++) {
            try {
               System.out.println(Thread.currentThread().getName() + ":" + (count++));
               Thread.sleep(100);
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
         }
      }
   }

   public int getCount() {
      return count;
   }
}

SyncThread的调用:

SyncThread syncThread = new SyncThread();
Thread thread1 = new Thread(syncThread, "SyncThread1");
Thread thread2 = new Thread(syncThread, "SyncThread2");
thread1.start();
thread2.start();

结果如下:

SyncThread1:0 
SyncThread1:1 
SyncThread1:2 
SyncThread1:3 
SyncThread1:4 
SyncThread2:5 
SyncThread2:6 
SyncThread2:7 
SyncThread2:8 
SyncThread2:9

  当两个并发线程(thread1和thread2)访问同一个对象(syncThread)中的synchronized代码块时,在同一时刻只能有一个线程得到执行,另一个线程受阻塞,必须等待当前线程执行完这个代码块以后才能执行该代码块。Thread1和thread2是互斥的,因为在执行synchronized代码块时会锁定当前的对象,只有执行完该代码块才能释放该对象锁,下一个线程才能执行并锁定该对象。

二、Java 基本数据类型与引用数据类型

基本数据类型:
byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0

short:短整型,在内存中占16位,即2个字节,取值范围-32768~32717,默认值0

int:整型,用于存储整数,在内在中占32位,即4个字节,取值范围-2147483648~2147483647,默认值 0

long:长整型,在内存中占64位,即8个字节-2^63~2^63-1,默认值0L

float:浮点型,在内存中占32位,即4个字节,用于存储带小数点的数字(与double的区别在于float类型有效小数点只有6~7位),默认值0

double:双精度浮点型,用于存储带有小数点的数字,在内存中占64位,即8个字节,默认值0

boolean:布尔类型,占1个字节,用于判断真或假(仅有两个值,即true、false),默认值false

/*代码实例*/
public class TestInit {
    boolean boo;
    char cha;
    byte by;
    short shor;
    int in;
    float flo;
    long lon;
    double dou;
    String str;

    @Test
    public void aa() {
        System.err.println("boolean:" + boo);
        if (cha == '\u0000') {
            System.err.println("char:" + (int) cha);
            System.err.println(cha);
        }
        System.err.println("byte:" + by);
        System.err.println("short:" + shor);
        System.err.println("int:" + in);
        System.err.println("long:" + lon);
        System.err.println("float:" + flo);
        System.err.println("double:" + dou);
        System.err.println("String:" + str);
    }
}

测试结果:

boolean:false
char:0
byte:0
short:0
int:0
long:0
float:0.0
double:0.0
String:null

三、Java值传递、引用传递、副本传递的区别

1、按值传递是什么?
 指的是在方法调用时,传递的参数是按值的拷贝传递。按值传递重要特点:传递的是值的拷贝,也就是说传递后就互不相关了.
实例:

 `public class TempTest {  
  private void test1(int a){  
    a = 5;  
    System.out.println("test1方法中的a="+a);  
  }  
  
  public static void main(String[] args) {  
    TempTest t = new TempTest();  
    int a = 3;  
    t.test1(a);//传递后,test1方法对变量值的改变不影响这里的a  
    System.out.println(”main方法中的a=”+a);  
  }  
}  

运行结果:

test1方法中的a=5  
main方法中的a=3 

2、按引用传递是什么?
 指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引用的地址,也就是变量所对应的内存空间的地址。传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)。

public class TempTest {  
  private void test1(A a){  
   a.age = 20;  
   System.out.println("test1方法中的age="+a.age);  
  }  
  
  public static void main(String[] args) {  
   TempTest t = new TempTest();  
   A a = new A();  
   a.age = 10;  
   t.test1(a);  
   System.out.println(”main方法中的age=”+a.age);  
  }  
}  

class A{  
  public int age = 0;  
}  

运行结果:

test1方法中的age=20  
main方法中的age=20  

相关参考博文:
Java:按值传递还是按引用传递详细解说
JAVA 值传递(副本传递)的理解

四、java实现快速排序算法


public class QuickSort {
    public static void main(String[] args) {
        int[] array = {12,15,85,65,32,78,68,32,45,78};//定义一个待排序数组
        quickSort(array,0,9);
        System.out.println(array);

    }

    public static void quickSort(int[] array,int low,int high){

        if (low < high) {
            int left = low;
            int right = high;
            int key = array[low];

            while(left < right){
                while(left < right && array[right] >= key )//从右向左找到第一个小于key的数字
                    right --;
                if(left < right)
                    array[left ++] = array[right];

                while(left < right && array[left] <= key)//从左向右找到第一个大于key的数
                    left ++;
                if (left < right) 
                    array[right --] = left;
            }

            array[left] = key;
            quickSort(array,low,left-1);//开始递归调用
            quickSort(array,high,right + 1);
        }   
    }
}

六、定义多个对象,使用不同的比较方法
java中的数据类型,可分为两类:
 1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean
他们之间的比较,应用双等号(==),比较的是他们的值。
 2.复合数据类型(类)
当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。
 对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的,因为Object的equals方法也是用双等号(==)进行比较的,所以比较后的结果跟双等号(==)的结果相同。
 

//代码实例
public class TestString {
  public static void main(String[] args) {
  String s1 = "Monday";
  String s2 = "Monday";
  if (s1 == s2)
  {
  System.out.println("s1 == s2");}
  else{
  System.out.println("s1 != s2");}
 } 
}

编译并运行程序,输出:s1 == s2说明:s1 与 s2 引用同一个 String 对象 – “Monday”!
2.再稍微改动一下程序,会有更奇怪的发现:

public class TestString {
 public static void main(String[] args) {
  String s1 = "Monday";
  String s2 = new String("Monday");
  if (s1 == s2){
   System.out.println("s1 == s2");
  }
  else{
   System.out.println("s1 != s2");
  }

  if (s1.equals(s2)) {System.out.println("s1 equals s2");}
  else{
   System.out.println("s1 not equals s2");
  }
 }
}

我们将s2用new操作符创建
程序输出:
s1 != s2
s1 equals s2
说明:s1 s2分别引用了两个”Monday”String对象
参考链接:Java中equals和==的区别
浅谈Java中的equals和==

七、Java中的开关语句Switch

“开关”(Switch)有时也被划分为一种“选择语句”。根据一个整数表达式的值,switch语句可从一系列
代码选出一段执行。它的格式如下:

switch(整数选择因子) { 
case 整数值1 : 语句; break; 
case 整数值2 : 语句; break; 
case 整数值3 : 语句; break; 
case 整数值4 : 语句; break; 
case 整数值5 : 语句; break; 
//.. 
default:语句; 

} 

八、java增强循环

For-Each循环
  For-Each循环也叫增强型的for循环,或者叫foreach循环。
  
  For-Each循环是JDK5.0的新特性(其他新特性比如泛型、自动装箱等)。
  For-Each循环的加入简化了集合的遍历。
  
其语法如下:
  for(type element: array) {
  
  System.out.println(element);
  
  }
  

/*增强循环实例*/
public class ForeachTest {

    public static void main(String[] args) {
        int[] array = {1,2,3,4,5,6,7,8,9};

        System.out.println("----------旧方式遍历------------");
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + " ");
        }
        System.out.println();

        System.out.println("---------增强循环遍历-------------");
            for (int i : array) {
                System.out.print(i + " ");

            }
        System.out.println();

        //二维数组遍历
        System.out.println("---------增强循环遍历二维数组-------------");
        int[][] array1 = {{11,22,33},{44,55,66},{77,88,99}};
        for (int[] is : array1) {
            for (int i : is) {
                System.out.print(i + " ");
            }
        }
        System.out.println();

    }
}

运行结果:

----------旧方式遍历------------
1 2 3 4 5 6 7 8 9 
---------增强循环遍历-------------
1 2 3 4 5 6 7 8 9 
---------增强循环遍历二维数组-------------
11 22 33 44 55 66 77 88 99 

总结

  上面所有说的知识点应该都是比较基础的,知识点也说的比较乱,从关键字一下子跳到了基本类型与引用类型,没有什么系统性的排版,但是这都是布置作业,作为学生也是没有什么办法的,只得照做,看到的就当时为自己查缺补漏吧,知识点也比较多,篇幅也比较长,自己的大家能耐心看就看下去,如果是针对某个知识点大家还是直接百度或Google来的更加直接些。
  知识点虽然比较基础的,但是对于我们初学者来说都是比较容易混淆的,比如== 和equals,都是傻傻分不清楚的。还有就是关于Arrays类中国的sort方法,看到有博文说在jdk1.5的时候,如果是基本类型比较,且数组长度小于7的话调用的就是插入排序,长度大于7就会调用快速排序,如果是引用类型的比较就是调用的归并排序,但是我这里JDK的版本是1.8的,查看源码时看到的都是调用的快速排序,自己由于也是初学者,所以也有点不清楚,待我与老师探讨探讨,得出结论在来确认修改,我们这里暂且默认为都是快速排序,毕竟源码摆在这里,也没有1.5版本的源码可查。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值