首页 文章 精选 留言 我的

精选列表

搜索[网站开发],共10000篇文章
优秀的个人博客,低调大师

iOS 开发之玩转专场动画

有空了再造个轮子,先放个链接 WWDC 2013 Session笔记 - iOS7中的ViewController切换 几句代码快速集成自定义转场效果+ 全手势驱动 TransitionAnimation 学习笔记 iOS --- 一张图看懂转场动画 iOS自定义转场动画实战讲解 iOS自定义转场动画实战讲解 iOS 视图控制器转场详解 iOS 视图控制器转场详解 iOS 转场动画探究(一) iOS 转场动画探究(二) iOS 转场动画详解 iOS自定义转场动画

优秀的个人博客,低调大师

Hadoop大数据开发框架学习

一.Hadoop框架介绍 hadoop是Apache发布的开源分布式基础架构他的两个核心是 HDFSHDFS是Hadoop的文件管理系统,负责了海量数据的存储,是做大数据的基础 MapReduceMapReduce则是为了海量数据提供了计算 两部分就组成了Hadoop的分布式基础架构 二.HDFS介绍 HDFS作为Hadoop为存储海量数据,自然有着与传统文件系统有着不同的结构,它是以Linux文件系统的基础的架构,构建里一套分布式文件系统,它是由一个NameNode和多台DataNode组成的。他通过将文件进行划分,分成多个数据块进行存储。(默认64MB,一般设置为128MB,备份X3)NameNode 管理文件系统的命名空间,存放文件元数据 维护文件系统的所有文件和目录,文件与数据块的映射 记录每个文件中各个块所在数据节点的信息 DataNode 存储并检索数据块 香NameNode更新所存储块的列表 优点 适合大文件存储,有副本策略 可以构建在廉价机器上,有一定容错和恢复机制 支持流式数据访问,一次写入多次读取 缺点 不适合大量小文件存储 不适合并发写入,不支持文件随机修改 不支持随机读等低延时的访问方式 二.Yarn yarn是Hadoop 中的资源管理器,MapReduce通过yarn来调度。ResourceManager 分配和调度资源 启动并监控ApplicationMaster 监控NodeManager ApplicationMaster 为MapReduce类型程序申请资源,并分配给内部任务 负责数据的切分 监控任务的执行与容错 NodeManager 管理单个节点的资源 处理来自ResourceManager的命令 处理来自ApplicationMaster的命令 四.MapReduce MapReduce采用分而治之的编程思想 输入一个大文件,通过split之后,将其分为多个分片 每个文件分片由单独的机器去处理,这就是Map方法 将每个机器计算的结果进行汇总并得到最终的结果,这就是Reduce方法

优秀的个人博客,低调大师

iOS 开发之 Fucking Block Syntax !

How Do I Declare A Block in Objective-C? As a local variable: returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...}; As a property: @property (nonatomic, copy, nullability) returnType (^blockName)(parameterTypes); As a method parameter: - (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName; As an argument to a method call: [someObject someMethodThatTakesABlock:^returnType (parameters) {...}]; As a typedef: typedef returnType (^TypeName)(parameterTypes); TypeName blockName = ^returnType(parameters) {...}; This is not intended to be an exhaustive list of all possible uses of blocks. If you find yourself needing syntax not listed here, it is likely that a typedef would make your code more readable. 原文

优秀的个人博客,低调大师

spring boot metrics信息推送开发

上一篇文章是关于 “spring boot +RabbitMQ +InfluxDB+Grafara监控实践” 主要讲spring boot应用新能监控信息的收集方案实践 实践是hystrix信息推送的mq而metrics信息需要扫描,文章的最后也有相应的思考metrics信息能不能是应用本身也推送到mq那? 本篇文章就实践关于metrics信息的推送实现 有了上面的思考之后我就回过头来去看hystrix是怎么实现推送的。经过一番跟踪之后找到了具体干活的task代码 有了这个代码就可以参考具体怎样实现metrics信息的推送了 但是还有一个问题就是metrics信息虽然暴露了url接口但是应用内我怎么获取那??? 这里又引发了我们一探究竟的兴趣!。。。。。。继续看源码!!!!!!!!!!! 从spring

优秀的个人博客,低调大师

Java 8 Stream--开发手册

什么是Java8 Stream,为什么需要Stream? Stream是Java8一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。 首先Java 8 Stream不是数据结构,它没有内部存储。它是为高效的集合(数组、List、Set……)操作而存在的。 Java中的集合Collection,具体包含:数组、List、Set等数据结构,都是由JDK提供的,难道在Java8之前的集合操作,有什么不便/局限吗? 下面给出一个需求进行对比,体验一下Java8 Stream:从一个List中,获取集合中每个对象的ID,返回一个新的ID List。 在Java8之前,我们需要这样做: List<Food> foods = new ArrayList<>(); // id price num foods.add(new Food(1, 5.5, 3)); foods.add(new Food(2, 4.5, 8)); foods.add(new Food(3, 56.5, 13)); foods.add(new Food(4, 9.5, 56)); // pre java8 List<Long> result = new ArrayList<>(); for (Food f: foods) { result.add(f.getId()); } 而Java8 Stream的方式: //java8 stream List<Long> collect = foods.parallelStream().map(each -> each.getId()).collect(toList()); 一行搞定,而且效率更高。 Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。 Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。 解析Stream通用语法 List<Integer> nums = new ArrayList<>(); nums.add(1); nums.add(null); nums.add(3); nums.add(null); nums.add(5); long count = nums.stream().filter(num -> num != null).count(); 上面这段代码是获取一个List中,元素不为null的个数。 image.png 图片就是对于Stream例子的一个解析,可以看到: 红色框中的语句是一个Stream的生命开始的地方,负责创建一个Stream实例; 绿色框中的语句是赋予Stream灵魂的地方,把一个Stream转换成另外一个Stream; 红框的语句生成的是一个包含所有nums变量的Stream, 经过绿框的filter方法以后,重新生成了一个新Stream,过滤掉原nums列表中所有为null的; 蓝色框中的语句是丰收的地方,把Stream的里面包含的内容按照某种算法来汇聚成一个值,例子中是获取Stream中非空元素个数。 在此我们总结一下使用Stream的基本步骤: 创建Stream; 流的操作(转换Stream,数据转换操作),每次转换原有Stream对象不改变,返回一个新的Stream对象(可以有多次转换); 对Stream进行聚合(Reduce)操作,获取想要的结果; 创建Stream Stream是在一个源的基础上创建出来的,例如java.util.Collection中的list或者set(map不能作为Stream的源)。有多种方式生成 Stream Source: 1、从集合中创建(最常见) Collection.stream() Collection.parallelStream() Arrays.stream(T array) or Stream.of() Collection的子类List、Set均可 2、静态工厂 java.util.stream.IntStream.range() java.nio.file.Files.walk() 3、BufferedReader java.io.BufferedReader.lines() 4、自定义创建:需要实现java.util.Spliterator接口 5、其它方式 Random.ints() BitSet.stream() Pattern.splitAsStream(java.lang.CharSequence) JarFile.stream() 构造流的几种常见方法 // 1. Individual values Stream stream = Stream.of("a", "b", "c"); // 2. Arrays String [] strArray = new String[] {"a", "b", "c"}; stream = Stream.of(strArray); stream = Arrays.stream(strArray); // 3. Collections List<String> list = Arrays.asList(strArray); stream = list.stream(); 流的操作(转换Stream) 流的操作,实际上就是通过转换Stream,完成对集合中数据转换的操作;如过滤出集合中特定元素等。 Stream中提供了很多方法,专门用于对集合中元素的各种操作;这些方法的参数都是lambda 表达式。 java.util.Stream表示了某一种元素的序列,在这些元素上可以进行各种操作。Stream操作可以是中间操作(Intermediate),也可以是终结操作(Terminal)。完结操作会返回一个某种类型的值,而中间操作会返回流对象本身,并且你可以通过多次调用同一个流操作方法来将操作结果串起来(就像StringBuffer的append方法一样)。 流的操作类型分为两种:终结操作(Terminal)和 非终结操作(Intermediate)。 Intermediate:非终结操作是核心,是真正处理数据转换的,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等。 一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。 Terminal:终结操作是对完成转换的数据进行汇合收集,是丰收的阶段。 一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。 Stream 典型用法 map 它的作用就是把 input Stream 的每一个元素,映射成 output Stream 的另外一个元素。 转换大写 List<String> output = wordList.stream().map(String::toUpperCase).collect(Collectors.toList()); 其中map() 是非终结操作, collect()是终结操作。这些方法的参数都是lambda 表达式。 计算平方数 List<Integer> nums = Arrays.asList(1, 2, 3, 4); List<Integer> squareNums = nums.stream(). map(n -> n * n). collect(Collectors.toList()); 这段代码生成一个整数 list 的平方数 {1, 4, 9, 16}。 从上面例子可以看出,map 生成的是个 1:1 映射,每个输入元素,都按照规则转换成为另外一个元素。 map方法示意图 image.png 还有一些场景,是一对多映射关系的,这时需要 flatMap。 flatMap一对多 Stream<List<Integer>> inputStream = Stream.of( Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5, 6) ); Stream<Integer> outputStream = inputStream. flatMap((childList) -> childList.stream()); flatMap 把 input Stream 中的层级结构扁平化,就是将最底层元素抽出来放到一起,最终 output 的新 Stream 里面已经没有 List 了,都是直接的数字。 filter filter 对原始 Stream 进行某项测试,通过测试的元素被留下来生成一个新 Stream。 留下偶数 Integer[] sixNums = {1, 2, 3, 4, 5, 6}; Integer[] evens = Stream.of(sixNums).filter(n -> n%2 == 0).toArray(Integer[]::new); 经过条件“被 2 整除”的 filter,剩下的数字为 {2, 4, 6}。 filter方法示意图: image.png limit/skip limit 返回 Stream 的前面 n 个元素;skip 则是扔掉前 n 个元素(它是由一个叫 subStream 的方法改名而来)。 对比limit 和 skip 对运行次数的影响 public void testLimitAndSkip() { List<Person> persons = new ArrayList(); for (int i = 1; i <= 10000; i++) { Person person = new Person(i, "name" + i); persons.add(person); } List<String> personList2 = persons.stream(). map(Person::getName).limit(10).skip(3).collect(Collectors.toList()); System.out.println(personList2); } private class Person { public int no; private String name; public Person (int no, String name) { this.no = no; this.name = name; } public String getName() { System.out.println(name); return name; } } 输出结果为: name1 name2 name3 name4 name5 name6 name7 name8 name9 name10 [name4, name5, name6, name7, name8, name9, name10] sorted 对 Stream 的排序通过 sorted 进行,它比数组的排序更强之处在于你可以首先对 Stream 进行各类 map、filter、limit、skip 甚至 distinct 来减少元素数量后,再排序,这能帮助程序明显缩短执行时间。 排序前进行 limit 和 skip List<Person> persons = new ArrayList(); for (int i = 1; i <= 5; i++) { Person person = new Person(i, "name" + i); persons.add(person); } List<Person> personList2 = persons.stream().limit(2).sorted((p1, p2) -> p1.getName().compareTo(p2.getName())).collect(Collectors.toList()); System.out.println(personList2); 结果输出为: name2 name1 [stream.StreamDW$Person@6ce253f1, stream.StreamDW$Person@53d8d10a] forEach forEach 方法接收一个 Lambda 表达式,然后在 Stream 的每一个元素上执行该表达式。 打印姓名(forEach 和 pre-java8 的对比) // Java 8 roster.stream() .filter(p -> p.getGender() == Person.Sex.MALE) .forEach(p -> System.out.println(p.getName())); // Pre-Java 8 for (Person p : roster) { if (p.getGender() == Person.Sex.MALE) { System.out.println(p.getName()); } } 对一个人员集合遍历,找出男性并打印姓名。可以看出来,forEach 是为 Lambda 而设计的,保持了最紧凑的风格。而且 Lambda 表达式本身是可以重用的,非常方便。当需要为多核系统优化时,可以 parallelStream().forEach(),只是此时原有元素的次序没法保证,并行的情况下将改变串行时操作的行为,此时 forEach 本身的实现不需要调整,而 Java8 以前的 for 循环 code 可能需要加入额外的多线程逻辑。 forEach 是 terminal 操作,因此它执行后,Stream 的元素就被“消费”掉了,你无法对一个 Stream 进行两次 terminal 运算。 相反,具有相似功能的 intermediate 操作 peek 可以达到上述目的。如下是出现在该 api javadoc 上的一个示例。 peek peek 对每个元素执行操作并返回一个新的 Stream Stream.of("one", "two", "three", "four") .filter(e -> e.length() > 3) .peek(e -> System.out.println("Filtered value: " + e)) .map(String::toUpperCase) .peek(e -> System.out.println("Mapped value: " + e)) .collect(Collectors.toList()); min/max/distinct min 和 max 的功能也可以通过对 Stream 元素先排序,再 findFirst 来实现,但前者的性能会更好,为 O(n),而 sorted 的成本是 O(n log n)。同时它们作为特殊的 reduce 方法被独立出来也是因为求最大最小值是很常见的操作。 找出最长一行的长度 BufferedReader br = new BufferedReader(new FileReader("c:\\SUService.log")); int longest = br.lines(). mapToInt(String::length). max(). getAsInt(); br.close(); System.out.println(longest); 下面的例子则使用 distinct 来找出不重复的单词。找出全文的单词,转小写,并排序 List<String> words = br.lines(). flatMap(line -> Stream.of(line.split(" "))). filter(word -> word.length() > 0). map(String::toLowerCase). distinct(). sorted(). collect(Collectors.toList()); br.close(); System.out.println(words); findFirst 这是一个 termimal 兼 short-circuiting 操作,它总是返回 Stream 的第一个元素,或者空。 这里比较重点的是它的返回值类型:Optional。这也是一个模仿 Scala 语言中的概念,作为一个容器,它可能含有某值,或者不包含。使用它的目的是尽可能避免 NullPointerException。 Optional 的两个用例 String strA = " abcd ", strB = null; print(strA); print(""); print(strB); getLength(strA); getLength(""); getLength(strB); public static void print(String text) { // Java 8 Optional.ofNullable(text).ifPresent(System.out::println); // Pre-Java 8 if (text != null) { System.out.println(text); } } public static int getLength(String text) { // Java 8 return Optional.ofNullable(text).map(String::length).orElse(-1); // Pre-Java 8 // return if (text != null) ? text.length() : -1; }; 在更复杂的 if (xx != null) 的情况中,使用 Optional 代码的可读性更好,而且它提供的是编译时检查,能极大的降低 NPE 这种 Runtime Exception 对程序的影响,或者迫使程序员更早的在编码阶段处理空值问题,而不是留到运行时再发现和调试。 Stream 中的 findAny、max/min、reduce 等方法等返回 Optional 值。还有例如 IntStream.average() 返回 OptionalDouble 等等。 reduce 这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。例如 Stream 的 sum 就相当于 Integer sum = integers.reduce(0, (a, b) -> a+b); 或 Integer sum = integers.reduce(0, Integer::sum); 也有没有起始值的情况,这时会把 Stream 的前面两个元素组合起来,返回的是 Optional。 reduce 的用例 // 字符串连接,concat = "ABCD" String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat); // 求最小值,minValue = -3.0 double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min); // 求和,sumValue = 10, 有起始值 int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum); // 求和,sumValue = 10, 无起始值 sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get(); // 过滤,字符串连接,concat = "ace" concat = Stream.of("a", "B", "c", "D", "e", "F"). filter(x -> x.compareTo("Z") > 0). reduce("", String::concat); 上面代码例如第一个示例的 reduce(),第一个参数(空白字符)即为起始值,第二个参数(String::concat)为 BinaryOperator。这类有起始值的 reduce() 都返回具体的对象。而对于第四个示例没有起始值的 reduce(),由于可能没有足够的元素,返回的是 Optional,请留意这个区别。 关于reduce理解起来比较抽象,下面通过笔者总结的一个用例具体演示。 需求1:求出每件Food 的总价(单品的总价=单价*数量) List<Food> foods = new ArrayList<>(); // id price num foods.add(new Food(1, 5.5, 3)); foods.add(new Food(2, 4.5, 8)); foods.add(new Food(3, 56.5, 13)); foods.add(new Food(4, 9.5, 56)); foods.stream().map(item->item.getPrice() * item.getNum()).forEach(System.out::print); 需求2:计算(所有Food)订单总价 double totalPrice = foods.stream().map(item->item.getPrice() * item.getNum()).reduce((sum,n)->sum+n).get(); 除了上面2种主要的终结操作(Terminal)和 非终结操作(Intermediate),还有一种Short-circuiting操作,包含以下函数: anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit Match Stream 有三个 match 方法,从语义上说: allMatch:Stream 中全部元素符合传入的 predicate,返回 true anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true 它们都不是要遍历全部元素才能返回结果。例如 allMatch 只要一个元素不满足条件,就 skip 剩下的所有元素,返回 false。对清单 13 中的 Person 类稍做修改,加入一个 age 属性和 getAge 方法。 使用Match List<Person> persons = new ArrayList(); persons.add(new Person(1, "name" + 1, 10)); persons.add(new Person(2, "name" + 2, 21)); persons.add(new Person(3, "name" + 3, 34)); persons.add(new Person(4, "name" + 4, 6)); persons.add(new Person(5, "name" + 5, 55)); boolean isAllAdult = persons.stream(). allMatch(p -> p.getAge() > 18); System.out.println("All are adult? " + isAllAdult); boolean isThereAnyChild = persons.stream(). anyMatch(p -> p.getAge() < 12); System.out.println("Any child? " + isThereAnyChild); 输出结果: All are adult? false Any child? true 效率问题 有人会有疑问:在对于一个Stream进行多次转换操作,每次都对Stream的每个元素进行转换,而且是执行多次,这样时间复杂度就是一个for循环里把所有操作都做掉的N(转换的次数)倍啊。其实不是这样的,转换操作都是lazy的,多个转换操作只会在汇聚操作(见下节)的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在汇聚操作的时候循环Stream对应的集合,然后对每个元素执行所有的函数。 Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,两种方式的使用也很简单,在创建Stream时,foods.stream()创建串行流,foods.parallelStream()创建并行流。 并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。 Stream并发模式,基于OS核心数,并行处理,有更高的执行效率。

优秀的个人博客,低调大师

iOS开发常用快捷键

一. Xcode基本快捷键 1、新建项目 Shift + CMD + N 2、项目中新建文件 CMD + N 3、运行 CMD + R 4、编译 CMD + B 5、停止运行 CMD + . 6、清除缓存 Shift + CMD + K 7、左缩进 CMD + [ 8、右缩进 CMD + ] 9、关闭项目 CMD + W 10、终止程序 CMD + Q 11、注释或取消注释 CMD + / 12、自动提示列表 ESC 二. 模拟器常用快捷键 1、模拟器Home键 Shift + CMD + H 2、模拟器截屏 CMD + S(默认保存到桌面) 3、模拟器截屏拷贝 Ctrl + CMD + C(保存在剪贴板) 4、模拟器转屏 CMD + → / CMD + ← 5、模拟器大小切换 CMD + 1/2/3/4 6、模拟器锁屏 CMD + L 7、文本框弹出键盘 CMD + K 8、文本框允许键盘输入 Shift + CMD + K 欢迎加群 四九6038六四九 学习交流,验证浇水 三、Xcode编辑快捷键 1、向上 Ctrl + P (previous) 2、向下 Ctrl + N (next) 3、向前 Ctrl + F (forward) 4、向后 Ctrl + B (back) 5、跳到一行的最前面 Ctrl + A (ahead) 6、跳到一行的最后面 Ctrl + E (end) 7、删除后面的字符 Ctrl + D (delete) 8、删除当前光标一行中所有后面文字 Ctrl + K 9、删除当前光标一行中所有后面文字 CMD + Delete 10、Control + Y: 将刚刚用Control+ K或CMD+ Delete删除的内容粘贴至光标所在之处 11、删除当前光标前面的一个单词 Ctrl + Delete 12、调换当前光标两边的字符Ctrl + T 13、将光标插入点置于窗口正中Ctrl + L 14、复制、剪切、粘贴、撤销略 四. Xcode常用快捷键(方向箭头类) 1、编辑界面向前 Ctrl + CMD + 右箭头 2、编辑界面向后 Ctrl + CMD + 左箭头 3、代码块折叠 CMD + Option + 左箭头 4、代码块展开 CMD + Option + 右箭头 5、展开或者折叠所有代码块 Shift + CMD + Option + 左右箭头 6、切换.m和.h文件 CMD + Ctrl + 上下箭头 7、跳到当前编辑器的最前或最后 CMD + 上下箭头 8、跳到行首或者行尾 CMD + 左右箭头 9、跳到本段的开头或者结尾 Option + 上下箭头 10、左右跳动一个单词 Option + 左右箭头 11、向前或者向后整行选中 Shift + 上下箭头 12、向前或者向后整段选中 Shift + Option + 上下箭头 13、向前选中所有先后选中所有 Shift + CMD +上下箭头 五. Xcode常用快捷键 1、选中光标所在的词 双击 2、选中光标所在的整行 三连击 3、焦点跳到工程导航器 CMD + 1 4、显示/隐藏导航器面板 CMD + 0(zero) 5、显示/隐藏实用工具面板Y CMD + Option + 0(zero) 6、显示/隐藏打印面板 Shift + CMD + Y 7、打开双视图并且在双视图右侧打开文件 Option+鼠标左键单击 8、关闭双视图 CMD + Enter 9、打开双视图 CMD+ Option + Enter 10、根据关键字快速切换到某一文件 CMD +Shift + O 11、打开API文档 Option+ 双击 12、快速打开方法或者关键字的帮助 Option +单击 13、展开项目中的所有文件夹 CMD +Shift + J 14、向前或者向后移动选中的代码 Option +CMD +左右括号

优秀的个人博客,低调大师

Android 插件开发--类加载器

1). Android中类加载器 Android 中常用的类加载器有DexClassLoader和PathClassLoader,其中PathClassLoader是Android应用中的默认加载器。 DexClassLoader可以加载任何路径下的apk/dex/jar/zip PathClassLoader只能加载/data/app中的apk,也就是已经安装在手机中的apk。 2). DexClassLoader 构造方法: public DexClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent) ; 其中: 继承自BaseDexClassLoader dexPath: 加载apk/dex/jar/zip的路径 optimizedDirectory: 是dex的输出路径 librarySearchPath: 加载时候需要用到的lib库,一般不用 parent: DexClassLoader指定的父加载器 3). PathClassLoader 构造方法: public PathClassLoader(String dexPath, ClassLoader parent); public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent); 其中 继承自BaseDexClassLoader dexPath: 加载dex路径 librarySearchPath: 加载时候需要用到的lib库 parent: PathClassLoader指定的父加载器 dex释放路径: /data/dalvik-cache 4). 查看各种类加载器 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); printMoreClassLoader(); } private static final String TAG = "MainActivity"; /** * 打印各种类加载器 */ private void printMoreClassLoader() { Log.d(TAG, "Context类的类加载器:" + Context.class.getClassLoader()); Log.d(TAG, "ListView类的类加载器:" + ListView.class.getClassLoader()); Log.d(TAG, "应用程序默认的类加载器:" + getClassLoader()); Log.d(TAG, "系统类加载器:" + ClassLoader.getSystemClassLoader()); Log.d(TAG, "系统类加载器和Context类的类加载器是否相等:" + (Context.class.getClassLoader() ==ClassLoader.getSystemClassLoader())); Log.d(TAG, "系统类加载器和应用程序默认加载器是否相等:" + (getClassLoader() == ClassLoader.getSystemClassLoader())); Log.d(TAG, "================================================"); Log.d(TAG, "打印应用程序默认加载器的委派机制:"); ClassLoader classLoader = getClassLoader(); while (null != classLoader) { Log.d(TAG, "类加载器: " + classLoader); classLoader = classLoader.getParent(); } Log.d(TAG, "================================================"); Log.d(TAG, "打印系统加载器的委派机制:"); classLoader = ClassLoader.getSystemClassLoader(); while (null != classLoader) { Log.d(TAG, "类加载器:" + classLoader); classLoader = classLoader.getParent(); } } 打印结果: Context类的类加载器:java.lang.BootClassLoader@8b6e11e ListView类的类加载器:java.lang.BootClassLoader@8b6e11e 应用程序默认的类加载器:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.mazaiting.dynamicjar-2/base.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_dependencies_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_0_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_1_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_2_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_3_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_4_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_5_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_6_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_7_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_8_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_9_apk.apk"],nativeLibraryDirectories=[/data/app/com.mazaiting.dynamicjar-2/lib/arm64, /system/lib64, /vendor/lib64]]] 系统类加载器:dalvik.system.PathClassLoader[DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /vendor/lib64, /system/lib64, /vendor/lib64]]] 系统类加载器和Context类的类加载器是否相等:false 系统类加载器和应用程序默认加载器是否相等:false ================================================ 打印应用程序默认加载器的委派机制: 类加载器: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.mazaiting.dynamicjar-2/base.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_dependencies_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_0_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_1_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_2_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_3_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_4_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_5_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_6_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_7_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_8_apk.apk", zip file "/data/app/com.mazaiting.dynamicjar-2/split_lib_slice_9_apk.apk"],nativeLibraryDirectories=[/data/app/com.mazaiting.dynamicjar-2/lib/arm64, /system/lib64, /vendor/lib64]]] 类加载器: java.lang.BootClassLoader@8b6e11e ================================================ 打印系统加载器的委派机制: 类加载器:dalvik.system.PathClassLoader[DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /vendor/lib64, /system/lib64, /vendor/lib64]]] 类加载器:java.lang.BootClassLoader@8b6e11e

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册