Groovy源代码分析(二)

2021SC@SDUSC

Groovy对Java类的扩展(上)


首先,我们来看一下groovy源码中有哪几个核心的包,如下图:

groovy的核心代码都在groovy-3.0.9这个jar包中,这个jar包中最重要的两个包分别是:groovy和org,而groovy中重点存的就是一些groovy对json,xml等处理的类,我们之后再详细讲解这个包中的核心类,今天我们分析的是org这个包中的核心类。而我们重点要讲解org/codehaus/groovy/runtime包中的核心类,其它包中的类则是一些辅助类,这个包中有如下几个类是我们要重点分析的,他们的类UML图如下所示:

 下面我来为大家解释一下这个类图,可以看到核心的一个父类就是DefaultGroovyMethodsSupport,而其它的类都是他的子类,子类有一个共同的特点就是类名都是:XXXGroovyMethods,那我们为什么说这几个类是核心类呢,了解过groovy的同学都应该知道,groovy是java的扩展,那groovy扩展了那些东西呢,除了我们还没有讲的groovy包中的一些类,另一部分的扩展就是我们图中的这些XXXGroovyMethods类中的方法,举个例子,大家来看下面这段代码:

String content = new File('config.txt').text
println content

这两句代码的作用非常的明显,就是获取到文件中的内容,并打印出来,在java中,我们要创建文件类,然后通过创建一个流来读取出文件内容,而且还要关闭文件流,可谓是非常的繁杂。而在groovy中则非常的清爽,下面我们看一下groovy是如何实现这个text方法的,代码如下:

//最终的实现就在这里,这个方法是在IOGroovyMethods类中
public static String getText(BufferedReader reader) throws IOException {
    StringBuilder answer = new StringBuilder();
    char[] charBuffer = new char[8192];

    try {
      int nbCharRead;
      while((nbCharRead = reader.read(charBuffer)) != -1) {
        answer.append(charBuffer, 0, nbCharRead);
      }

      Reader temp = reader;
      reader = null;
      temp.close();
    } finally {
      closeWithWarning(reader);
    }

    return answer.toString();
  }

通过这段代码可以看到,Groovy底层的实现与Java原来的实现完全一样,只是groovy替我们完成了封装使得我们可以直接通过getText()方法来得到整个文本文件的内容。从这个方法,我们就可以看出groovy对java所作的扩展有多么的强大。

这也就是我们为什么要重点看这几个类,了解了这几个类的话就基本可以清楚地知道groovy对java做了那些扩展。

下面我们就分别来看一下这几个类是为java中的类做了那些扩展,我们首先来看一下DefaultGroovyMethods这个方法做了那些扩展,首先大家
要知道的是,这个类是对所有java中的类的一个扩展,也就是java中的任何一个类,在groovy中都是可以使用DefaultGroovyMethods中的方法的,下面我们来看一些比较常用的方法:

public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
  private static final Logger LOG = Logger.getLogger(DefaultGroovyMethods.class.getName());
  private static final Integer ONE = Integer.valueOf(1);
  private static final BigInteger BI_INT_MAX = BigInteger.valueOf(2147483647L);
  private static final BigInteger BI_INT_MIN = BigInteger.valueOf(-2147483648L);
  private static final BigInteger BI_LONG_MAX = BigInteger.valueOf(9223372036854775807L);
  private static final BigInteger BI_LONG_MIN = BigInteger.valueOf(-9223372036854775808L);
  public static final Class[] additionals = new Class[]{NumberNumberPlus.class, NumberNumberMultiply.class, NumberNumberMinus.class, NumberNumberDiv.class, ObjectArrayGetAtMetaMethod.class, ObjectArrayPutAtMetaMethod.class, BooleanArrayGetAtMetaMethod.class, BooleanArrayPutAtMetaMethod.class, ByteArrayGetAtMetaMethod.class, ByteArrayPutAtMetaMethod.class, CharacterArrayGetAtMetaMethod.class, CharacterArrayPutAtMetaMethod.class, ShortArrayGetAtMetaMethod.class, ShortArrayPutAtMetaMethod.class, IntegerArrayGetAtMetaMethod.class, IntegerArrayPutAtMetaMethod.class, LongArrayGetAtMetaMethod.class, LongArrayPutAtMetaMethod.class, FloatArrayGetAtMetaMethod.class, FloatArrayPutAtMetaMethod.class, DoubleArrayGetAtMetaMethod.class, DoubleArrayPutAtMetaMethod.class};
  public static final Class[] DGM_LIKE_CLASSES = new Class[]{DefaultGroovyMethods.class, DateGroovyMethods.class, EncodingGroovyMethods.class, IOGroovyMethods.class, ProcessGroovyMethods.class, ResourceGroovyMethods.class, SocketGroovyMethods.class, StringGroovyMethods.class};
  private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
  private static final NumberAwareComparator<Comparable> COMPARABLE_NUMBER_AWARE_COMPARATOR = new NumberAwareComparator();

  public DefaultGroovyMethods() {
  }

  //用来直接判断other对象是否与调用对象相等
  public static boolean is(Object self, Object other) {
    return self == other;
  }
  //直接判断迭代器中的对象是否是唯一的
  public static <T> Iterator<T> unique(Iterator<T> self) {
    return toList((Iterable)unique(toList(self))).listIterator();
  }

  public static <T> Collection<T> unique(Collection<T> self) {
    return unique(self, true);
  }
  //任意对象都都可以使用each方法来进行遍历,当然如果是不可迭代对象,会报错
 public static <T> T each(T self, Closure closure) {
    each(InvokerHelper.asIterator(self), closure);
    return self;
  }

  public static <T> T eachWithIndex(T self, Closure closure) {
    Object[] args = new Object[2];
    int counter = 0;
    Iterator iter = InvokerHelper.asIterator(self);

    while(iter.hasNext()) {
      args[0] = iter.next();
      args[1] = Integer.valueOf(counter++);
      closure.call(args);
    }

    return self;
  }

这里就不一一列出了,这个类是对java对象做的一个扩展。

下面我们再来看StringGroovyMethods,从这个类的类名我们就可以看出,这个类是针对java中的String做的扩展,下面我们来看一下这个类中对Java中的String类做了那些扩展:

public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
  static String lineSeparator = null;

  public StringGroovyMethods() {
  }

  public static String uncapitalize(CharSequence self) {
    String s = self.toString();
    return s != null && s.length() != 0?Character.toLowerCase(s.charAt(0)) + s.substring(1):s;
  }
  //将String首字母大写,这个方法非常的常用,尤其在自定义Task时候
  public static String capitalize(CharSequence self) {
    return self.length() == 0?"":"" + Character.toUpperCase(self.charAt(0)) + self.subSequence(1, self.length());
  }
  //遍历字符串中的每个字符,并将对应的字符应用闭包
  public static <T> T eachLine(CharSequence self, @ClosureParams(value = FromString.class,options = {"String", "String,Integer"}) Closure<T> closure) throws IOException {
    return eachLine((String)self.toString(), 0, closure);
  }

  public static <T> T eachLine(CharSequence self, int firstLine, @ClosureParams(value = FromString.class,options = {"String", "String,Integer"}) Closure<T> closure) throws IOException {
    int count = firstLine;
    T result = null;

    for(Iterator var5 = readLines(self.toString()).iterator(); var5.hasNext(); ++count) {
      String line = (String)var5.next();
      result = DefaultGroovyMethods.callClosureForLine(closure, line, count);
    }

    return result;
  }

其它的方法,我们也不再列出,可见通过StringGroovyMethods对方法的扩展,可以极大的方便我们的开发。

而ResourceGroovyMethods和IOGroovyMethods则是对文件IO流的扩展。一些常用的方法如下:

//获取文件中的字节码 
 public static byte[] getBytes(File file) throws IOException {
    return IOGroovyMethods.getBytes(new FileInputStream(file));
  }

 public static byte[] getBytes(InputStream is) throws IOException {
    ByteArrayOutputStream answer = new ByteArrayOutputStream();
    byte[] byteBuffer = new byte[8192];

    int nbByteRead;
    try {
      while((nbByteRead = is.read(byteBuffer)) != -1) {
        answer.write(byteBuffer, 0, nbByteRead);
      }
    } finally {
      closeWithWarning(is);
    }

    return answer.toByteArray();
  }

//获取文件中的每一行内容,并对其应用闭包
public static <T> T eachLine(Reader self, @ClosureParams(value = FromString.class,options = {"String", "String,Integer"}) Closure<T> closure) throws IOException {
    return eachLine((Reader)self, 1, closure);
  }

  public static <T> T eachLine(Reader self, int firstLine, @ClosureParams(value = FromString.class,options = {"String", "String,Integer"}) Closure<T> closure) throws IOException {
    int count = firstLine;
    T result = null;
    BufferedReader br;
    if(self instanceof BufferedReader) {
      br = (BufferedReader)self;
    } else {
      br = new BufferedReader(self);
    }

    try {
      while(true) {
        String line = br.readLine();
        if(line == null) {
          Reader temp = self;
          self = null;
          temp.close();
          Object var7 = result;
          return var7;
        }

        result = DefaultGroovyMethods.callClosureForLine(closure, line, count);
        ++count;
      }
    } finally {
      closeWithWarning(self);
      closeWithWarning(br);
    }
  }
//获取每行文件内容并返回调用者
public static String readLine(Reader self) throws IOException {
    if(self instanceof BufferedReader) {
      BufferedReader br = (BufferedReader)self;
      return br.readLine();
    } else {
      return self.markSupported()?readLineFromReaderWithMark(self):readLineFromReaderWithoutMark(self);
    }
  }
//对每个字节使用闭包,与eachLine作用类似
public static void eachByte(InputStream is, @ClosureParams(value = SimpleType.class,options = {"byte"}) Closure closure) throws IOException {
    try {
      while(true) {
        int b = is.read();
        if(b == -1) {
          InputStream temp = is;
          is = null;
          temp.close();
          return;
        }

        closure.call(Byte.valueOf((byte)b));
      }
    } finally {
      closeWithWarning(is);
    }
  }

这是我举出来的这两个类中的常用方法,可以看到,有了groovy对IO流的扩展,我们可以直接对文件,流进行更方便的操作。

最后一个比较重要的就是我们的EncodingGroovyMethods,这个类我们通过名字也可以看出, 是与编解码相关的扩展,代码如下:

public class EncodingGroovyMethods {
    private static final char[] T_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();
    private static final char[] T_TABLE_URLSAFE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=".toCharArray();
    private static final String CHUNK_SEPARATOR = "\r\n";
    private static final String MD5 = "MD5";
    private static final String SHA_256 = "SHA-256";

    public EncodingGroovyMethods() {
    }

    public static Writable encodeBase64(Byte[] data, boolean chunked) {
        return encodeBase64(DefaultTypeTransformation.convertToByteArray(data), chunked);
    }

    public static Writable encodeBase64(Byte[] data) {
        return encodeBase64(DefaultTypeTransformation.convertToByteArray(data), false);
    }

    public static Writable encodeBase64(byte[] data, boolean chunked) {
        return encodeBase64(data, chunked, false, true);
    }

    private static Writable encodeBase64(final byte[] data, final boolean chunked, final boolean urlSafe, final boolean pad) {
        return new Writable() {
            public Writer writeTo(Writer writer) throws IOException {
                int charCount = 0;
                int dLimit = data.length / 3 * 3;
                char[] table = urlSafe ? EncodingGroovyMethods.T_TABLE_URLSAFE : EncodingGroovyMethods.T_TABLE;

                int dx;
                for(dx = 0; dx != dLimit; dx += 3) {
                    int d = (data[dx] & 255) << 16 | (data[dx + 1] & 255) << 8 | data[dx + 2] & 255;
                    writer.write(table[d >> 18]);
                    writer.write(table[d >> 12 & 63]);
                    writer.write(table[d >> 6 & 63]);
                    writer.write(table[d & 63]);
                    if (chunked) {
                        ++charCount;
                        if (charCount == 19) {
                            writer.write("\r\n");
                            charCount = 0;
                        }
                    }
                }

                if (dLimit != data.length) {
                    dx = (data[dLimit] & 255) << 16;
                    if (dLimit + 1 != data.length) {
                        dx |= (data[dLimit + 1] & 255) << 8;
                    }

                    writer.write(table[dx >> 18]);
                    writer.write(table[dx >> 12 & 63]);
                    if (pad) {
                        writer.write(dLimit + 1 < data.length ? table[dx >> 6 & 63] : 61);
                        writer.write(61);
                    } else if (dLimit + 1 < data.length) {
                        writer.write(table[dx >> 6 & 63]);
                    }

                    if (chunked && charCount != 0) {
                        writer.write("\r\n");
                    }
                }

                return writer;
            }

            public String toString() {
                StringBuilderWriter buffer = new StringBuilderWriter();

                try {
                    this.writeTo(buffer);
                } catch (IOException var3) {
                    throw new StringWriterIOException(var3);
                }

                return buffer.toString();
            }
        };
    }

    public static Writable encodeBase64(byte[] data) {
        return encodeBase64(data, false);
    }

    public static Writable encodeBase64Url(Byte[] data) {
        return encodeBase64Url(data, false);
    }

    public static Writable encodeBase64Url(Byte[] data, boolean pad) {
        return encodeBase64Url(DefaultTypeTransformation.convertToByteArray(data), pad);
    }

    public static Writable encodeBase64Url(byte[] data) {
        return encodeBase64Url(data, false);
    }

    public static Writable encodeBase64Url(byte[] data, boolean pad) {
        return encodeBase64(data, false, true, pad);
    }

    public static byte[] decodeBase64(String value) {
        return decodeBase64(value, false);
    }

    public static byte[] decodeBase64Url(String value) {
        return decodeBase64(value, true);
    }

    private static byte[] decodeBase64(String value, boolean urlSafe) {
        int byteShift = 4;
        int tmp = 0;
        boolean done = false;
        StringBuilder buffer = new StringBuilder();
        byte[] table = urlSafe ? EncodingGroovyMethodsSupport.TRANSLATE_TABLE_URLSAFE : EncodingGroovyMethodsSupport.TRANSLATE_TABLE;

        for(int i = 0; i != value.length(); ++i) {
            char c = value.charAt(i);
            int sixBit = c < '{' ? table[c] : 66;
            if (sixBit < 64) {
                if (done) {
                    throw new RuntimeException("= character not at end of base64 value");
                }

                tmp = tmp << 6 | sixBit;
                if (byteShift-- != 4) {
                    buffer.append((char)(tmp >> byteShift * 2 & 255));
                }
            } else if (sixBit == 64) {
                --byteShift;
                done = true;
            } else if (sixBit == 66) {
                throw new RuntimeException("bad character in base64 value");
            }

            if (byteShift == 0) {
                byteShift = 4;
            }
        }

        return buffer.toString().getBytes(StandardCharsets.ISO_8859_1);
    }

    public static Writable encodeHex(Byte[] data) {
        return encodeHex(DefaultTypeTransformation.convertToByteArray(data));
    }

    public static Writable encodeHex(final byte[] data) {
        return new Writable() {
            public Writer writeTo(Writer out) throws IOException {
                byte[] var2 = data;
                int var3 = var2.length;

                for(int var4 = 0; var4 < var3; ++var4) {
                    byte datum = var2[var4];
                    String hexString = Integer.toHexString(datum & 255);
                    if (hexString.length() < 2) {
                        out.write("0");
                    }

                    out.write(hexString);
                }

                return out;
            }

            public String toString() {
                StringBuilderWriter buffer = new StringBuilderWriter();

                try {
                    this.writeTo(buffer);
                } catch (IOException var3) {
                    throw new StringWriterIOException(var3);
                }

                return buffer.toString();
            }
        };
    }

    public static byte[] decodeHex(String value) {
        if (value.length() % 2 != 0) {
            throw new NumberFormatException("odd number of characters in hex string");
        } else {
            byte[] bytes = new byte[value.length() / 2];

            for(int i = 0; i < value.length(); i += 2) {
                bytes[i / 2] = (byte)Integer.parseInt(value.substring(i, i + 2), 16);
            }

            return bytes;
        }
    }

    public static String md5(CharSequence self) throws NoSuchAlgorithmException {
        return digest(self, "MD5");
    }

    public static String md5(byte[] self) throws NoSuchAlgorithmException {
        return digest(self, "MD5");
    }

    public static String sha256(CharSequence self) throws NoSuchAlgorithmException {
        return digest(self, "SHA-256");
    }

    public static String sha256(byte[] self) throws NoSuchAlgorithmException {
        return digest(self, "SHA-256");
    }

    public static String digest(CharSequence self, String algorithm) throws NoSuchAlgorithmException {
        String text = self.toString();
        return digest(text.getBytes(StandardCharsets.UTF_8), algorithm);
    }

    public static String digest(byte[] self, String algorithm) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance(algorithm);
        md.update(ByteBuffer.wrap(self));
        return encodeHex(md.digest()).toString();
    }
}

这个类中的方法也很明显,我们可以将String编码为Base64码,16进制字节码,也可以反向解析。

虽然org包中的类也非常的多,但是需要重点关注的就是这几个类(除去还未讲的groovy包下的类)。而这些对应的扩展方法的使用与我们使用类中已经定义的普通方法完全一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值