手记

Groovy核心类源码讲解(上)

2018-07-14 23:00:137218浏览

qndroid

1实战 · 15手记 · 17推荐

上一篇文章我们重点分析了android-gradle-plugin的几个核心类以及通过UML类图了解了这些核心类的一个相互依赖关系,不管是什么类型的Plugin其实还是基于gradle这个编程框架,不同的Plugin只是为了实现特定的功能而已,而gradle这个框架的核心类呢,大家可以参考学习我的gradle3.0实战课程去了解学习。今天我们重点来带领大家学习一下gradle的底层基础groovy的核心类,至于gradle与groovy的关系,与java和android的关系完全一样,下面,我们就来看一下groovy中的一些核心类的源码。让大家对gradle有一个更加深入的了解。
首先,我们来看一下groovy源码中有那几个核心的包,如下图:

所有的groovy代码都在groovy-all-2.4.11这个是jar包中,这个jar包中最重要的两个包分别是:groovy和org,而groovy中重点存的就是一些groovy对json,xml等处理的类,我们下回再详细讲解这个包中的核心类,今天我们重点来分析一下org这个包中的核心类。org包中的所以类,我这里就不再为大家截图了,大家自行查看jar包中的代码即可,下面我们来讲解我们重点要讲解的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();
  }

通过这段代码可以看到,他底层的实现与我们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 String CHUNK_SEPARATOR = "\r\n";

  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(final byte[] data, final boolean chunked) {
    return new Writable() {
      public Writer writeTo(Writer writer) throws IOException {
        int charCount = 0;
        int dLimit = data.length / 3 * 3;

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

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

          writer.write(EncodingGroovyMethods.T_TABLE[d >> 18]);
          writer.write(EncodingGroovyMethods.T_TABLE[d >> 12 & 63]);
          writer.write(dLimit + 1 < data.length?EncodingGroovyMethods.T_TABLE[d >> 6 & 63]:61);
          writer.write(61);
          if(chunked && charCount != 0) {
            writer.write("\r\n");
          }
        }

        return writer;
      }

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

        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 byte[] decodeBase64(String value) {
    int byteShift = 4;
    int tmp = 0;
    boolean done = false;
    StringBuilder buffer = new StringBuilder();

    for(int i = 0; i != value.length(); ++i) {
      char c = value.charAt(i);
      int sixBit = c < 123?EncodingGroovyMethodsSupport.TRANSLATE_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;
      }
    }

    try {
      return buffer.toString().getBytes("ISO-8859-1");
    } catch (UnsupportedEncodingException var8) {
      throw new RuntimeException("Base 64 decode produced byte values > 255");
    }
  }

  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 {
        for(int i = 0; i < data.length; ++i) {
          String hexString = Integer.toHexString(data[i] & 255);
          if(hexString.length() < 2) {
            out.write("0");
          }

          out.write(hexString);
        }

        return out;
      }

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

        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;
    }
  }
}

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

虽然org包中的类也非常的多,但是大家要重点关注的就是这几个类(除去还未讲的groovy包下的类)。这些对应的扩展方法的使用与我们使用类中已经定义的普通方法完全一样,不了解的同学可以通过我的gradle实战课程去学习。

好,本节的内容就到这里,本小节的内容相对简单,主要就是带大家熟悉了几个重要的扩展类,那,这些扩展类中的方法是如何绑定到java中的对应对象上的呢,这部分内容就比较复杂了,我们会在下一篇文章中详细为大家讲解,感兴趣的同学可以先去了解一下groovy中的元编程,否则不太好理解下一节内容。

8人推荐
随时随地看视频
慕课网APP