Java速通 Day2 – 方法,包装,字符串工具

/ 0评 / 0

其实前一节已经写了一些方法,在C中我们叫做函数,其中入口的叫Main的方法,今天好好研究下这个方法.

把程序写成这样的最小形式,然后编译成字节码运行一遍看看.

package com.hello;

public class basic {
    public static void main(String[] args) {
        for(String arg : args) {
            System.out.println(arg);
        }
    }
}

把class编译出来.

然后执行看看.

C:\Users\TaterLi\IdeaProjects\HelloWorld\src\com\hello>java -classpath C:\Users\TaterLi\IdeaProjects\HelloWorld\src com.
hello.basic 123 456
123
456

把我们输入的两个参数都遍历出来了.

第一天时候其实已经用过一些方法,比如Math.sqrt就是Math的静态方法sqrt,之前求factorial时候用的函数有返回值long和输入值long,当然对于Java返回一个long []也是毫无问题的,Java也支持重载同一个函数,当他编译成字节码后是不一样的.下面是重载实验.

package com.hello;

import java.util.Arrays;

public class basic {
    public static String[] addSome(String[] arr) {
        String[] newArr = new String[arr.length];
        for (int i = 0; i < arr.length; i++) {
            newArr[i] = arr[i] + "xxx";
        }
        return newArr;
    }

    public static long[] addSome(long[] arr) {
        long[] newArr = new long[arr.length];
        for (int i = 0; i < arr.length; i++) {
            newArr[i] = arr[i] + 1000L;
        }
        return newArr;
    }

    public static void main(String[] args) {
        String [] str_arr = {"hello", "world"};
        long [] long_arr = {1L,2L,3L};

        System.out.println(Arrays.toString(addSome(str_arr)));
        System.out.println(Arrays.toString(addSome(long_arr)));
    }
}

他运行也是完全正常的.

这一点和C++很像.

前面说了很多都是基本类型在搞来搞去,Java中还特别搞了个包装类型,包装就是一个箱子,他里面存放的是你数值的另一个形式,因此,他可以表达更大,更宽的数据,既然是箱子,那当然要支持拆箱了,所以拆成什么,就看程序需要了.

package com.hello;

public class basic {
    public static void main(String[] args) {
        // 数值包装类型下面以Integer举例,其它包装类型的用法同Integer,包括Byte、Short、Long、Float、Double
        // 初始化包装变量的第一种方式:直接用等号赋值
        Integer oneInteger = 1;
        // 初始化包装变量的第二种方式:调用包装类型的valueOf方法
        //Integer oneInteger = Integer.valueOf(1);
        // 初始化包装变量的第三种方式:使用关键字new创建新变量
        //Integer oneInteger = new Integer(1);

        System.out.println("oneInteger="+oneInteger);
        byte oneByte = oneInteger.byteValue(); // 把包装变量转换成字节变量
        System.out.println("oneByte="+oneByte);
        short oneShort = oneInteger.shortValue(); // 把包装变量转换成短整变量
        System.out.println("oneShort="+oneShort);
        int oneInt = oneInteger.intValue(); // 把包装变量转换成整型变量
        System.out.println("oneInt="+oneInt);
        long oneLong = oneInteger.longValue(); // 把包装变量转换成长整变量
        System.out.println("oneLong="+oneLong);
        float oneFloat = oneInteger.floatValue(); // 把包装变量转换成浮点变量
        System.out.println("oneFloat="+oneFloat);
        double oneDouble = oneInteger.doubleValue(); // 把包装变量转换成双精度变量
        System.out.println("oneDouble="+oneDouble);
    }
}

运行结果如下.

oneInteger=1
oneByte=1
oneShort=1
oneInt=1
oneLong=1
oneFloat=1.0
oneDouble=1.0

同样属于包装类型的还有Boolean,数值的包装类型可以直接用加减乘除和求余,也可以用包装类型的对应方法比如Integer.sum,逻辑的包装类型能进行逻辑运算.也可以用类似Boolean.logicalXor的方法进行运算,当你用普通符号运算时候,JVM会发生自动拆箱自动装箱各种操作,我觉得方便来说当然是直接当他普通类型用了.可能Java搞那么多就是为了照顾众人胃口吧.

如果说前面的包装类型只是换了个表达罢了,那BigInteger(可表达任意大整数)和BigDecimal(可表达精确小数)就太牛逼了,之前会溢出的大小,这里都不成问题了,当然如果这是不可精确表达的小数,那么就会出错,需要使用手段保证只保留一定的位数.

保留小数位数可以直接传递参数,也可以使用MathContext,有时候觉得Java提供了太多方法,也不是什么好事,经常头疼该用什么方法.

package com.hello;

import java.math.BigInteger;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

public class basic {
    public static void main(String[] args) {
        BigDecimal one = BigDecimal.valueOf(100);
        BigDecimal three = BigDecimal.valueOf(3); // 生成一个指定数值的大小数变量
        BigDecimal sevenAndHalf = BigDecimal.valueOf(7.5); // 生成一个指定数值的大小数变量

        BigInteger nine = BigInteger.valueOf(9); // 生成一个指定数值的大整数变量
        BigInteger four = BigInteger.valueOf(4); // 生成一个指定数值的大整数变量

        BigInteger sum = nine.add(four); // add方法用来替代加法运算符“+”
        System.out.println("sum="+sum);
        BigDecimal sub = sevenAndHalf.subtract(three); // subtract方法用来替代减法运算符“-”
        System.out.println("sub="+sub);
        BigDecimal mul = sevenAndHalf.multiply(three); // multiply方法用来替代乘法运算符“*”
        System.out.println("mul="+mul);
        BigDecimal remainder = sevenAndHalf.remainder(three); // remainder方法用来替代取余数运算符“%”
        System.out.println("remainder="+remainder);
        BigDecimal neg = sevenAndHalf.negate(); // negate方法用来替代负号运算符“-”
        System.out.println("neg="+neg);
        BigDecimal abs = sevenAndHalf.abs(); // abs方法用来替代数学库函数Math.abs
        System.out.println("abs="+abs);
        BigDecimal pow = sevenAndHalf.pow(2); // pow方法用来替代数学库函数Math.pow
        System.out.println("pow="+pow);

        // 大小数的除法运算,小数点后面保留64位,其中最后一位做四舍五入
        BigDecimal div = one.divide(three, 64, BigDecimal.ROUND_HALF_UP);
        System.out.println("div="+div);

        // 利用工具MathContext,可以把divide方法的输入参数减少为两个
        MathContext mc = new MathContext(64, RoundingMode.HALF_UP);
        BigDecimal divByMC = one.divide(three, mc); // 根据指定的精度规则执行除法运算
        System.out.println("divByMC="+divByMC);
    }
}

这里回忆一个问题,我们似乎从来没用过char,都是在用String,看这样,难不成String真的是包装类型?还真是!因为基本类型只有char,但是我们只用一个字符这样的场合也太少了,所以平时都是用String,为了验证,我做了如下尝试.

package com.hello;

public class basic {
    public static void main(String[] args) {
        char a = 'a';
        char [] b = {'H','e','l','l','o'};
        char c = '\\';
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
    }
}

得到结果.

a
Hello
\

特别说明的是char在Java中是16bit的,所以他可以表达65535那么大的数字,char也可以通过普通类型强转成其他类型,但是似乎在Java中这种操作是很少见的,char也有自己的包装类型Character,这个包装类型也有自己的方法charValue,当然由于他是一个Character,他也有一些特殊的方法.

boolean isDigit = Character.isDigit(letter); // isDigit方法判断字符是否为数字
boolean isLetter = Character.isLetter(letter); // isLetter方法判断字符是否为字母
boolean isLowerCase = Character.isLowerCase(letter); // isLowerCase方法判断字符是否为小写
boolean isUpperCase = Character.isUpperCase(letter); // isUpperCase方法判断字符是否为大写
boolean isSpaceChar = Character.isSpaceChar(line); // isSpaceChar方法判断字符是否为空格
boolean isWhitespace = Character.isWhitespace(line);// isWhitespace方法判断字符是否为空白
char lowerCase = Character.toLowerCase(letter); // toLowerCase方法把字符转换为大写
char upperCase = Character.toUpperCase(letter); // toUpperCase方法把字符转换为小写

在以往我们写C语言代码时候,字符串明明是一个数组存在的,所以他是不是也可以打散到char或者Character呢,显然打散成char是很简单的.

public class basic {
    public static void main(String[] args) {
        String s1 = "Hello World";
        for (int i = 0; i < s1.length(); i++) {
            System.out.println(s1.charAt(i));
        }
    }
}

如果是Character就需要多一点点...

public class basic {
    public static void main(String[] args) {
        String s1 = "Hello World";
        Character [] s2 = new Character[s1.length()];
        for (int i = 0; i < s1.length(); i++) {
            s2[i] = s1.charAt(i);
            System.out.println(s2[i]);
        }
    }
}

看起来包装类型也就完成了...吗?不是的,记得刚才那个大数,我们平时怎么给他附初值,明显一个非常非常打的数是不能直接写的,难不成每次为了得到一个大数先做因式分解吗?不现实,所以就提供了String转BigDecimal/BigInteger的方法.

public class basic {
    public static void main(String[] args) {
        String s1 = "123456789.98765432";
        BigDecimal d1 = new BigDecimal(s1);
        System.out.println(d1);
    }
}

有了包装类型,Java处理这些数据比C简单多了,但是String这个超级常用的包装类型,他还有更多更多的用途.就像C语言里的printf,他明明可以传入格式转换符,是不是Java也有.

当然的,他格式化后返回的就是String类型,除了没有%p这种在C语言代表指针的玩意,其他基本都是兼容的.比如%2d,%.8f,%-8c等等.

public class basic {
    public static void main(String[] args) {
        String s1 = String.format("第一个正整数是 %d 吗?",1);
        System.out.println(s1);
    }
}

字符串能做的事情还不止这些,有很多只有字符串才能用的函数,毕竟我们很多时候都是在进行字符串的各种比较嘛.

String hello = "Hello World. 你好世界。";
boolean isEmpty = hello.isEmpty(); // isEmpty方法判断该字符串是否为空串
boolean equals = hello.equals("你好"); // equals方法判断该字符串是否与目标串相等
boolean startsWith = hello.startsWith("Hello"); // startsWith方法判断该字符串是否以目标串开头
boolean endsWith = hello.endsWith("World"); // endsWith方法判断该字符串是否以目标串结尾
boolean contains = hello.contains("or"); // contains方法判断该字符串是否包含了目标串
int char_length = hello.length(); // length方法返回该字符串的字符数
int byte_length = hello.getBytes().length; // getBytes方法返回该字符串对应的字节数组
char first = hello.charAt(0); // charAt方法返回该字符串在指定位置的字符
int index = hello.indexOf("l"); // indexOf方法返回目标串在源串中第一次找到的位置
int lastIndex = hello.lastIndexOf("l"); // lastIndexOf方法返回目标串在源串中最后一次找到的位置
String lowerCase = hello.toLowerCase(); // toLowerCase方法返回转换为小写字母的字符串
String upperCase = hello.toUpperCase(); // toUpperCase方法返回转换为大写字母的字符串
String trim = hello.trim(); // trim方法返回去掉首尾空格后的字符串
String concat = hello.concat("Fine, thank you."); // concat方法返回在末尾添加目标串后的字符串
String subToEnd = hello.substring(6);// 只有一个输入参数的substring方法,从指定位置一直截取到源串的末尾
String subToCustom = hello.substring(6, 9);// 有两个输入参数的substring方法,返回从开始位置到结束位置中间截取的子串
String replace = hello.replace("l", "L"); // replace方法返回目标串替换后的字符串

最后字符串还可以跟正则扯上关系,分别是matches和split方法,他们传入的都是正则表达式,这里matches和前面的contains不要搞混,一个是输入字符串,一个是输入正则表达式,但是我看来他们明明都是一个中文意思,实在没办法了,也只能纯记忆了,这里就给出一个简单例子.

package com.hello;

public class basic {
    // 校验四位的年份字符串
    public static void checkYear() {
        String regex = "(19|20)\\d{2}"; // 四位年份数字必须以19或者20开头
        for (int i = 1899; i <= 2100; i++) {
            if (i > 1910 && i < 2090) { // 缩小待校验年份的区间范围
                continue;
            }
            String year = i + "";
            boolean check = year.matches(regex); // 校验该年份是否匹配正则表达式的规则
            System.out.println("year = " + year + ", check = " + check);
        }
    }

    // 通过算术的加减乘除符号来分割字符串
    private static void splitByArith() {
        String arithStr = "123+456*789-123/456%789";
        // 正则串里的加号、星号、横线都要转义,加减乘除符号之间通过竖线隔开
        String[] arithArray = arithStr.split("\\+|\\*|\\-|/|%");
        for (String item : arithArray) { // 遍历并打印分割后的字符串数组元素
            System.out.println("arith item = " + item);
        }
    }

    public static void main(String[] args) {
        checkYear();
        splitByArith();
    }
}

正则表达式是不是有点难,很多人都惧怕正则表达式,简单解释一下,两个斜杠代表的是保留原始意思,比如上面的\\+,因为+是正则里面符号,\\+就是匹配加号,不要当他是正则里的+意义,而是普通字符+,|就是OR,就是多个条件,()包含的就是一部分运算,其实正则多看看别人写的,慢慢也就领悟了.

今天就先到这里了.

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注