JAVA高级语言重要概念以及重要的类之一(进程、线程、Runtime类、比较器、正则表达式、反射机制等)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gyshun/article/details/84277932

1、进程与线程

根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位。

在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。

所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)

内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。

包含关系:没有线程的进程可以看做是单线程的,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。

在JAVA中实现多线程有两种途经:

  • 继承Thread类
  • 实现Runnable接口(Callable接口)

继承Thread类实例代码:

class MyThread extends Thread{
    private String name;
    public MyThread(String name){
        this.name = name;
    }
    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println(this.name+"---->"+i);
        }
    }
}
public class ThreadStudyTest {
    public static void main(String[] args) {
         MyThread m1 = new MyThread("线程A");
         MyThread m3 = new MyThread("线程B");
         MyThread m2 = new MyThread("线程C");
         m1.start();//启动线程
         m2.start();
         m3.start();
    }
}

利用Runnable来实现多线程,

class MyRunnableThread implements Runnable{
    private String name;
    public MyRunnableThread(String name){
        this.name = name;
    }
    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println("线程:"+this.name+"---->"+i);
        }
    }
}
public class RunnableThreadTest {
    public static void main(String[] args) {
       new Thread(new MyRunnableThread("A")).start();
       new Thread(new MyRunnableThread("B")).start();
       new Thread(new MyRunnableThread("C")).start();
    }
}

注意Runnable中只有一个方法run();如果要启动线程,需要借助Thread类来完成,只有Thread类有线程操作的所有方法。

两者实现的区别

  • Thread类是Runnable接口的子类,使用Runnable接口实现多线程能够避免单继承局限
  • Runnable接口实现的多线程可能比Thread类更加方便数据共享

第三种实现方式:Callable,

扫描二维码关注公众号,回复: 4311967 查看本文章

由于Runnable接口实现可以避免单继承的局限,但是不能返回一个操作结果。为了解决这个问题,提供了一个Callable接口,但是这个接口操作起来难度大一些。

这个接口是在java.util包中,而Runnable是在java.lang包中,如下图是Callable接口:

从上图中就可以看出返回的结果类型是在声明类的时候定义。

线程休眠方法:Thread.sleep(1000L); 是线程处于休眠状态,但是资源没有释放。

线程优先级:越高的优先级,有可能越先执行。在JAVA中,对线程优先级操作提供了两个方法:

  • 设置优先级:publlic final void setPriority(int newPriority);
  • 取得优先级:public final int getPriority();

对于优先组的取值都是使用Int数据类型,对于此数据类型在Thread类中设置了三种取值:

  • 最高优先级:public static final int MAX_PRIORITY;对应的常量是:10
  • 中等优先级:public static final int NORM_PRIORITY;对应的常量 是:5
  • 最低优先级:public static final int MIN_PRIORITY;对应的常量是:1

2、Runtime类

Runtime类是一个单例模式的类,通过Runtime.getRuntime()来获取Runtime类,那么Runtime类主要 作用是:

Runtime类是直接与本地运行的所有相关属性的集合,主要的方法有:

  • 返回所有的可用内存:public long totalMemory();
  • 返回最大可用内存:public long maxMemory();
  • 返回空余内存空间:public long freeMemory();
public class RuntimeTest {
    public static void main(String[] args) {
        Runtime rt = Runtime.getRuntime();
        System.out.println(rt.maxMemory());
        System.out.println(rt.totalMemory());
        System.out.println(rt.freeMemory());
    }
}

Runtime类可以调用本机的可执行程序,并且创建进程;

执行程序的方法:public Process exec(String command) throws IOException

如下代码是调用本机的画图程序:

public class RuntimeTest {
    public static void main(String[] args) {
        Runtime rt = Runtime.getRuntime();
      /*  System.out.println(rt.maxMemory());
        System.out.println(rt.totalMemory());
        System.out.println(rt.freeMemory());*/
        try {
           Process ps = rt.exec("mspaint.exe");
           Thread.sleep(2000L);
           ps.destroy();//关掉执行程序
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Runtime类提供了gc()方法,可以调用垃圾回收器,操作内存。

3、final finally finalize这三者有什么区别?

  • final:是关键字,定义不能继承的类、不能被覆写的方法和常量。
  • finally:是关键字,异常的统一出口
  • finalize:是Object类提供的一个方法(protected void finalize() throws Throwable),指的是对象收回的方法,即使出现了异常也不到于程序中断。

4、对象克隆

对象克隆就是对象的复制操作,在Object类里面提供有一个专门的克隆方法,此方法会抛出一个“CloneNotSupportedException”异常。如下代码:

class Book2 implements Cloneable {
    private String titel;
    private double price;

    public Book2(String titel, double price) {
        this.titel = titel;
        this.price = price;
    }


    public String getTitel() {
        return titel;
    }

    public void setTitel(String titel) {
        this.titel = titel;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "书名:" + this.titel + ":价格是:" + this.price;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class CloneTest {
    public static void main(String[] args) {
     Book2 ba = new Book2("JAVA开发",23.4);
        Book2 bb = null;
        try {
            bb = (Book2) ba.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        bb.setTitel("Python");
        System.out.println(ba.toString());
        System.out.println(ba.toString());
    }
}

注意:Object类中的clone()方法是protected,需要子类进行重写,并把protected改成public,子类才能调用。

5、Math、Random、BigInteger、

Math类就是专门用于数学计算的操作类,里面提供了一系列的数学计算方法。

在Math类里面提供的一切方法都是static型的方法,因为Math类里面没有普通属性。

Random类是取得随机数的操作类。

大数字操作类:BigInterger、BigDecimal 这两个,当double存放不了数据可以用这个两个类中进行操作,但是JAVA本身提供的这两个大数字操作类相对来说比较简单,如果有大数字的复杂计算需求,就需要找专门的第三方工具。

BigDecimal类是可以保存小数的,可以进行精确的四舍五入操作,可以保留多位小数,而Math.round()是四舍五入之后,全部是整型了。

下面是Math、Random、BigInteger、Decimal这四个类的重要方法的代码:

class MyMath{
    public static double divide(double d,int scale){
        BigDecimal big = new BigDecimal(d);
        BigDecimal big2 = new BigDecimal(1);
     return big.divide(big2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
    }
}
public class ImportantClassTest {
    public static void main(String[] args) {
        System.out.println(Math.PI);
        System.out.println(Math.round(15.5));//16
        System.out.println(Math.round(-15.5));//-15
        System.out.println(Math.round(-15.51));//16
        Random ran = new Random();
        for (int i = 0; i <10 ; i++) {
            System.out.print(ran.nextInt(100)+"   ");
        }
        System.out.println();
        BigInteger big1 = new BigInteger("379646476738678346");
        BigInteger big2 = new BigInteger("78896768678");
        System.out.println(big1.add(big2));
        System.out.println(big1.subtract(big2));
        System.out.println(big1.multiply(big2));
        System.out.println(big1.divide(big2));
        System.out.println(big1.divideAndRemainder(big2));

        System.out.println(MyMath.divide(23.44555666,2));
    }
}

6、Date、Calendar、SimpleDateFormat三个类的关系

这三个类是对日期时间数据进行转换和使用。

其中Date的构造有两种:

  • 无参构造:public date();
  • 有参构造 :public date(long date);
  • 转换为long型:public long getTime();
public class DateClassTest {
    public static void main(String[] args) {
        long dateLong = System.currentTimeMillis();
        Date date = new Date();
        Date date2 = new Date(dateLong);
        System.out.println(date);
        System.out.println(date2);
    }
}

SimpleDateFormat类主要解决日期格式化操作

  • 构造方法 public SimpleDateFormat(String pattern);
  • 将Date转换为String:public final String format(Date date );
  • 将String转换为Date:public Date parse(String source) throws parseException;

 Calendar类主要是进行简单的日期计算使用,如下代码:

public class DateClassTest {
    public static void main(String[] args) {
       /* long dateLong = System.currentTimeMillis();
        Date date = new Date();
        Date date2 = new Date(dateLong);
        System.out.println(date);*/
       Calendar c = Calendar.getInstance();
       StringBuffer sb = new StringBuffer();
       sb.append(c.get(Calendar.YEAR)+"-");
       sb.append(c.get(Calendar.MONTH)+1+"-");
       sb.append(c.get(Calendar.DAY_OF_MONTH)+"  ");
       sb.append(c.get(Calendar.HOUR_OF_DAY)+":");
       sb.append(c.get(Calendar.MINUTE)+":");
       sb.append(c.get(Calendar.SECOND));

        System.out.println(sb.toString());

    }
}

7、比较器的使用

主要介绍Arrays类、两种比较器的使用你以及数据结构(二叉树)。

Arrays类:在这个类中有一个方法存在二分查找法:

public static int binarySearch();

要实现二分查找法,首先数组中必须是经过排序的数据,才能进行二分查的,效率是非常高,如下代码:

public class ComparableClassTest {
    public static void main(String[] args) {
        int[] array = new int[]{1,2,3,4,9,6,5,8,0};
        //使用二分查找法,数组是必须先排序
        Arrays.sort(array);
        //对于二分查找法,如果能查到数据,返回它在数组中的索引,否则返回负值
        System.out.println(Arrays.binarySearch(array,10));

    }
}

Arrays中有一个方法是把数组转换成字符串来输出:public static String toString(int[] a);

比较器:Comparable

在Arrays类中有一个方法可以实现对象数组排序:public static void sort(Object a);是因为数组中的对象都实现了Comparable接口。例如下面代码:

class BookComparable implements Comparable<BookComparable>{
    @Override
    public int compareTo(BookComparable o) {
        if (this.price >o.price) {
           return 1;
        }else if(this.price < o.price){
            return -1;
        }else {
            return 0;
        }

    }

    private String titel;
    private double price;

    public BookComparable(String titel, double price) {
        this.titel = titel;
        this.price = price;
    }

    public String getTitel() {
        return titel;
    }

    public void setTitel(String titel) {
        this.titel = titel;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return
                "titel='" + titel + '\'' +
                ", price=" + price ;
    }
}
public class ComparableClassTest {
    public static void main(String[] args) {
       /* int[] array = new int[]{1,2,3,4,9,6,5,8,0};
        //使用二分查找法,数组是必须先排序
        Arrays.sort(array);
        //对于二分查找法,如果能查到数据,返回它在数组中的索引,否则返回负值
        System.out.println(Arrays.binarySearch(array,10));*/
        BookComparable book = new BookComparable("JAVA",87.8);
        BookComparable book2 = new BookComparable("JAVA2",98.8);

        System.out.println(book.compareTo(book2));


    }
}

注意:对于对象数组进行排序,是直接调用Comparable接口的方法,数组中的对象必须进行实现。

比较器:Comparator

Comparator是一个函数式接口,如下代码:

class BookComparable implements Comparable<BookComparable>{
    @Override
    public int compareTo(BookComparable o) {
        if (this.price >o.price) {
           return 1;
        }else if(this.price < o.price){
            return -1;
        }else {
            return 0;
        }

    }

    private String titel;
    private double price;

    public BookComparable(String titel, double price) {
        this.titel = titel;
        this.price = price;
    }

    public String getTitel() {
        return titel;
    }

    public void setTitel(String titel) {
        this.titel = titel;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return
                "titel='" + titel + '\'' +
                ", price=" + price ;
    }
}
class  BookComparator implements Comparator<BookComparable> {
    @Override
    public int compare(BookComparable o1, BookComparable o2) {
        if (o1.getPrice() >o2.getPrice()) {
            return 1;
        }else if(o1.getPrice() < o2.getPrice()){
            return -1;
        }else {
            return 0;
        }
    }
}
public class ComparableClassTest {
    public static void main(String[] args) {
       /* int[] array = new int[]{1,2,3,4,9,6,5,8,0};
        //使用二分查找法,数组是必须先排序
        Arrays.sort(array);
        //对于二分查找法,如果能查到数据,返回它在数组中的索引,否则返回负值
        System.out.println(Arrays.binarySearch(array,10));*/
        BookComparable books [] = new BookComparable[] { new BookComparable("JAVA",87.8)
        , new BookComparable("JAVA2",98.8)};
         Arrays.sort(books,new BookComparator());
        System.out.println(Arrays.toString(books));


    }
}

说明:两种比较器(Comparable、Comparator)区别

  • 如果对象数组要进行排序,那么必须设置排序规划,可以使用Comparable或Comparator接口都可以
  • java.lang.Comparable是一个类定义的时候实现好的接口,这样对象数组就可以进行排序,在Comparable接口下定义有一个public int compareTo()方法
  • java.util.Comparetor是专门定义一个指定类的比较规则,属于挽救的比较操作,里面有两个方法:public int compare();public int equal();

我们经常使用的是Comparable接口。

8、正则表达式

       在所有的开发一定有有正则的支持,记下常用的正则标记以及掌握String类对正则的支持。

正则表达式是对字符串进行操作,正则是从JDK 1.4之后正式引入到JAVA工具中,所有正则支持的类都在java.util.regex包中。

在java.util.regex中定义了两个类:

  • Pattern类:此类对象要想取得,必须调用compile()方法,这个方法是用来编译正则类。
  • Matcher类:通过Pattern类取得

正则标记:

1、单个字符:(数量:1)

  • 字符:表示由一个字符组成
  • \\:表示转义字符"\"
  • \t:表示tab
  • \n:表示换号

2、字符集:(数量:1)

  • [abc]:表示可能是字符a或者字符b或者是字符c中的任意一个。
  • [^abc]:表示不是abc中的任意一位。
  • [a-z]:所有的小定字母
  • [A-Za-z]:表示所有的大小写字母
  • [0-9]:表示任意一位数字

3、简化的字符集表达式:(数量:1)

  • .:表示任意一个字符,包括数字、大小写字母以及各种特殊字符
  • \d:等价于[0-9],是简化写法
  • \D:等价于[^0-9],也是简化写法
  • \s:表示任意的空白字符,例如:空格(\t)、回车(\n)
  • \S:表示任意的非空白字符
  • \w:等价于[a-z][A-Z][0-9],表示任意的字母、数字以及_下划线组成
  • \W:表示上面的非

4、边界匹配:(不要在JAVA中使用,在JS中使用)

  • ^:正则的开始
  • $:正则的结束

5、数量表达

  • 正则?:表示此正则出现0次或1次
  • 正则+:表示此正则出现一次或者一次以上
  • 正则*:表示此正则可以出现0次、一次或者 多次
  • 正则{n}:表示此正则可以出现n次
  • 正则{n,}:表示此正则可以出现n次以上(包含n次)
  • 正则{n,m}:表示此正则可以出现n次和M次之间

6、逻辑运算:

  • 正则1正则2:正则1判断完成之后继续判断正则2
  • 正则1|正则2:表示正则1或者正则2有一组满足即可
  • (正则):将多个正则作为一组,可以为这一组设置出现的次数。

String类对正则的支持:

代码如下:

public class RegulerExpressClassTest {
    public static void main(String[] args) throws ParseException {
        String str = "akljkdlfjiue90#$%^&@%JHKHS&D*(^&#%57136767()*&(*&*^$#$kljkljkj33&&^#JKLjklk11";
        String regex = "[^a-z]";
        //去掉所有的非小写字母
        System.out.println(str.replaceAll(regex,""));
        //下面代码是通过正则进行分组
        String str2 = "kljkljklj23kljlk45kljklj6hjhjh6jhjh8hjhjh0werw3rew3r2w3er33";
        String regex2 = "\\d+";
        String[] splitStr = str2.split(regex2);
        for (int i = 0; i < splitStr.length; i++) {

                System.out.println(splitStr[i]);

            }
        //验证一个字符串是否是数字,如果是变成double型
        String str3 = "344555.2";
        String regex3 = "\\d+(\\.\\d+)?";
        System.out.println(str3.matches(regex3));
        if (str3.matches(regex3) ) {
            System.out.println(Double.parseDouble(str3));
        }
        //判断是否是日期类型进行转换输出
        String str4 = "2018-09-09";
        String regex4 = "\\d{4}-\\d{2}-\\d{2}";
        if (str4.matches(regex4)){
            Date date = new SimpleDateFormat("yyyy-MM-dd").parse(str4);
            System.out.println(date.toString());
        }
       //判断电话号码 格式一:51283345 格式二:010-12345678 格式三:(010)-59823123
        String str5 = "010-4567890";
        String numberRegex = "(\\d{3,4}-)?\\d{7,8}";

        System.out.println(str5.matches(numberRegex));
        //使用正则判断邮箱
        String str6 = "[email protected]";
        String regex6 = "\\w+@\\w+\\.\\w+";
        System.out.println(str6.matches(regex6));
    }
}

9、反射机制

从三个方面进行讲解:首先认识反射,其次理解反射的机制,最后了解通过反射调用类的结构。

 反射机制的话先通过“反"来理解,既然有"反"就有正,什么是正?

所谓“正”就是先有类再有对象。

所谓“反”就是通过对象找到对象的出处,在Object类里面提供有一个方法:

取得Class对象:public final Calss<?> getClass();

Class类对象的实例化

java.lang.Class是一个类,这个类是反射操作的源头,即,所有的反射都要从此类开始,这个类有三个实例化方法:

  • 调用Object类中的getClass()方法(用的相对少一些)
public class reflexClassTest {
    public static void main(String[] args) {
        Date d = new Date();
        Class<?> c = d.getClass();
        System.out.println(c.toString());
    }
}
  • 使用类.class中获得
public class reflexClassTest {
    public static void main(String[] args) {
      //  Date d = new Date();
        //Class<?> c = d.getClass();
        Class<?> c = Date.class;
        System.out.println(c.toString());
    }
}
  • 调用Class类提供的一个方法

 public static Class<?> forName(String className) throws ClassNotFoundException;

public class reflexClassTest {
    public static void main(String[] args) throws ClassNotFoundException {
      //  Date d = new Date();
        //Class<?> c = d.getClass();
        //Class<?> c = Date.class;
        Class<?> c = Class.forName("java.util.Date");
        System.out.println(c.toString());
    }
}

取得类对象,就要反射实例化对象

一旦拿到Class对象,就可以通过反射机制来实例化对象。

实例化对象方法:public T newInstance() throws InstantiationException,IilegalAccessException;

如下代码所示:

class  BookReflex{
    public BookReflex() {
        System.out.println("-----------------------");
    }

    @Override
    public String toString() {
        return "这是一本书";
    }
}
public class reflexClassTest {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class<?> book = Class.forName("BookReflex");
        Object obc = book.newInstance();
        BookReflex b = (BookReflex) obc;
        System.out.println(b.toString());

    }
}

为什么要使用反射机制?

通过反射机制能够设计出松耦合的架构。new是耦合的最大元凶;

调用构造方法:

通过获得Constructor类来执行有参构造,默认情况下是调用无参构造,如果没有无参构造就会报异常(如果类中没有任何构造方法,就会默认是无参构造方法):NoSuchMethodException;

调用有参构造:

class  BookReflex{
    private String title;
    private double price;

    public BookReflex(String title, double price) {
        this.title = title;
        this.price = price;
    }


    @Override
    public String toString() {
        return "书的名字是:"+this.title+"   "+"价格是:"+this.price;
    }
}
public class reflexClassTest {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<?> book = Class.forName("BookReflex");
        Constructor<?> con = book.getConstructor(String.class,double.class);

        Object obc = con.newInstance("这本书!",89);
        BookReflex b = (BookReflex) obc;
        System.out.println(b.toString());

    }
}

反射调用普通方法:

普通方法是对象实例后才能调用。对象的实例化方法有三种:new方法、克隆方法、反射机制

在Class类中提供方法有:

  • 取得所有的方法的对象:public Method[] getMethods();
  • 取得指定方法名称的方法对象:public Method getMethod(String methodName,Class<?>...parameterTyper);

上面两个方法都是返回Method对象,那么Method对象我们关注哪些方法:

  • 调用方法:public Object invoke(Object obj,Object...args) throws IilegalAccessException;

代码如下:

class  BookReflex{
    private String title;
    private double price;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}
public class reflexClassTest {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {
        String str = "title";
        Class<?> book = Class.forName("BookReflex");

        Object obc = book.newInstance();
        Method setM = book.getMethod("set"+initMethod(str),String.class);
        Method getM = book.getMethod("get"+initMethod(str));
           setM.invoke(obc,"这是一本JAVA书!");
        System.out.println(getM.invoke(obc));
    }
    public static String initMethod(String str){
        return str.substring(0,1).toUpperCase()+str.substring(1);
    }
}

反射调用成员:

在Class类中获得成员的方法:

  • 取得全部成员:public Field[] getDeclaredFields() throws SecurityException;
  • 取得指定成员:public Field getDeclaredField(String name) throws NoSuchFieldException,SecurityException;

上面的代码返回的类型是Field类,这个类中有两个重要的方法

  • 取得属性内容:public Object get(Object obj) ;
  • 设置属性内容:public void set(Object obj,Object value);

代码如下:

class  BookReflex{
    private String title;

}
public class reflexClassTest {
    public static void main(String[] args) throws Exception {
        String str = "title";
        Class<?> book = Class.forName("BookReflex");

        Object obc = book.newInstance();
        Field field = book.getDeclaredField(str);
        //通过下面的设置,类中的私有属性也能访问(打破封装)
        field.setAccessible(true);
        field.set(obc,"java开发!");

        System.out.println( field.get(obc));
    }

}

从上面的代码,对于私有的方法可以取消封装,不过,我们很少使用,建议还是使用get与set方法。

更多JAVA高级语言的特性,请查看续集:JAVA高级语言重要概念以及重要的类之二(文件操作、字节流、字符流、转换流、缓冲流、内存流、打印流、扫描流等)

猜你喜欢

转载自blog.csdn.net/gyshun/article/details/84277932