工作需要,开始写原生安卓项目;本文记录一个前端学习安卓相关知识的历程
https://www.cdsy.xyz/computer/programme/java/20210305/cd16149327239109.html 可用于快速补充一些 Java 的基础知识,作为一个基本的工具手册。Java 是一门强类型的面向对象的解释型语言,通过JVM可以在多平台运行。
8 种内置类型,六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型:
引用类型
对象、数组都是引用数据类型,所有引用类型的默认值都是null。
对前端而言,需要额外注意两点:
总的来说,Java 基本语法和一般程序语言的语法一致。相比JS,我们可能要注意 修饰符,接口等概念。
和 JS 基本一致;不过可以注意下增强的 for 循环:
- String [] names ={"James", "Larry", "Tom", "Lacy"};
- for( String name : names ) {
- System.out.print( name );
- System.out.print(",");
- }
for(声明语句 : 表达式) 中表达式为数组。
与 JS 一致。
对象是类的一个实例,有状态和行为。类可以看成是创建Java对象的模板。一个类可以包含以下类型变量:
每个类都有构造方法。如果没有显式为类定义构造方法,Java编译器将会为该类提供一个默认构造方法。
包主要用来对类和接口进行分类。我们用package pkgName 来声明包,用import java.io.* 来引入包。
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java支持4种不同的访问权限。
为了实现一些其他的功能,Java也提供了许多非访问修饰符。
Java是完全面向对象的语言,继承是最重要的topic。Java只有单继承(相比多继承,减少复杂度和潜在的一些问题(比如函数重写)),但通过接口来保留多继承的一些优点。
典型的继承语法:
- class Pet {
- public String name;
- private int age = 0;
- public Pet() {}
- public String getName() {
- System.out.println("yes, in Pet!");
- return name;
- }
- public int getAge() {
- return age;
- }
- }
-
- interface Animal {
- public void eat(String food);
- }
-
- class Dog extends Pet implements Animal {
- int age = 10;
-
- @Override
- public int getAge() {
- System.out.println("hey!" + age);
- return age;
- }
-
- public void eat(String food) {
- System.out.println("dog eat " + food);
- }
- }
-
- public class Test {
- public static void main(String[] args) {
- Pet a = new Pet();
- Pet b = new Pet();
- Dog d = new Dog();
- System.out.println(a.getName());
- System.out.println(d.getName());
- System.out.println("--------------");
- d.eat("gouliang");
- }
- }
子类可以从父类继承所有的 protected/public 属性和方法。
我们知道,JS 中,基于原型链的继承机制,所有实例的方法调用的方法最终都指向原型(链)的某个方法,即方法在内存中只有一份,那在Java中一样吗?
答案是:是。
Java中,类在加载时,类的信息(类信息,常量,静态变量,类方法)被存储到方法区。
类信息除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量、符号引用,文字字符串、final变量值、类名和方法名常量,这部分内容将在类加载后存放到方法区的运行时常量池中。它们以数组形式访问,是调用方法、与类联系及类的对象化的桥梁。
其中 方法信息,包括方法名、返回值类型、参数类型、修饰符、异常、方法的字节码。
在Java中 new 一个对象时,为类的成员(包括(继承的)父类的成员)分配了内存空间,然后执行构造函数,初始化这些属性的值。
但对象并不会为方法分配内存,当调用对象的方法时,实质上是去方法区查找到对应的方法执行。
静态方法和私有方法在解析阶段确定唯一的调用版本,而其它实例方法,会去动态查找(沿继承链)。
参考:
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map。
泛型类的定义:
- class 类名称 <泛型标识:可以随便写任意标识号,标识指定的泛型的类型>{
- private 泛型标识 /*(成员变量类型)*/ var;
- .....
- }
- }
例子:
- class Demo <T> {
- private T key;
- public Demo(T key) {
- this.key = key;
- }
- public T getKey() {
- return key;
- }
- }
- // 泛型的类型参数只能是类类型(包括自定义类),不能是简单类型
- // 传入的实参类型需与泛型的类型参数类型相同,即为Integer.
- Demo<Integer> demoInt = new Demo<Integer>(10);
泛型的类型参数只能代表引用型类型,不能是原始类型(像int,double,char等)
- //定义一个泛型接口
- public interface Generator<T> {
- public T next();
- }
-
- public class FruitGenerator implements Generator<String> {
-
- private String[] fruits = new String[]{"Apple", "Banana", "Pear"};
-
- @Override
- public String next() {
- Random rand = new Random();
- return fruits[rand.nextInt(3)];
- }
- }
泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型 。
- public class GenericMethodTest
- {
- // 泛型方法 printArray
- public static < E > void printArray( E[] inputArray )
- {
- // 输出数组元素
- for ( E element : inputArray ){
- System.out.printf( "%s ", element );
- }
- System.out.println();
- }
-
- public static void main( String args[] )
- {
- // 创建不同类型数组: Integer, Double 和 Character
- Integer[] intArray = { 1, 2, 3, 4, 5 };
- Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
- Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
-
- System.out.println( "Array integerArray contains:" );
- printArray( intArray ); // 传递一个整型数组
-
- System.out.println( "\nArray doubleArray contains:" );
- printArray( doubleArray ); // 传递一个双精度型数组
-
- System.out.println( "\nArray characterArray contains:" );
- printArray( charArray ); // 传递一个字符型型数组
- }
- }
有界的类型参数:
可能有时候,你会想限制那些被允许传递到一个类型参数的类型种类范围。例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例。这就是有界类型参数的目的。
要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界。
- // 比较三个值并返回最大值
- // T 必须继承自 Comparable 接口
- public static <T extends Comparable<T>> T maximum(T x, T y, T z)
- {
- T max = x; // 假设x是初始最大值
- if ( y.compareTo( max ) > 0 ){
- max = y; //y 更大
- }
- if ( z.compareTo( max ) > 0 ){
- max = z; // 现在 z 更大
- }
- return max; // 返回最大对象
- }
源于同事的一次分享,查阅资料了解了Java虚拟机和内存管理相关知识。利于深入了解Java,对比JS可能有更大收获。
It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors.
虽然逻辑上来说,方法区也是堆的一部分,不过方法区一般不被GC管理(取决于JVM的具体实现)。
下载 AndroidStudio,创建一个项目并编译,了解基本的流程。
Gradle 是一个基于 JVM 的构建工具,基于 groovy,有强大的依赖管理,支持多工程构建。
projects 和 tasks是 Gradle 中最重要的两个概念。
1、创建任务
1.1、创建一个最简单的task(build.gradle文件):
- task hello {
- doLast {
- println 'Hello world!'
- }
- }
我们可以执行gradle -q hello查看输出:
- $ gradle -q hello
- Hello world!
1.2、快速定义task:
- task hello << {
- println 'Hello world!'
- }
- // << 等同于 doLast
1.3、使用groovy
- task upper << {
- String someString = 'mY_nAmE'
- println "Original: " + someString
- println "Upper case: " + someString.toUpperCase()
- }
- $ gradle -q upper
- Original: mY_nAmE
- Upper case: MY_NAME
2、任务依赖
2.1、 在两个任务之间指明依赖关系
- task hello << {
- println 'Hello world!'
- }
- task intro(dependsOn: hello) << {
- println "I'm Gradle"
- }
- $ gradle -q intro
- Hello world!
- I'm Gradle
2.2、延迟依赖
taskX 是可以在 taskY 之前定义的。
- task taskX(dependsOn: 'taskY') << {
- println 'taskX'
- }
- task taskY << {
- println 'taskY'
- }
3、动态任务
- 4.times { counter ->
- task "task$counter" << {
- println "I'm task number $counter"
- }
- }
- // gradle -q task1
4、任务操纵
4.1、通过 API 进行任务之间的通信 - 增加依赖
- 4.times { counter ->
- task "task$counter" << {
- println "I'm task number $counter"
- }
- }
- task0.dependsOn task2, task3
4.2、通过 API 进行任务之间的通信 - 增加任务行为
- task hello << {
- println 'Hello Earth'
- }
- hello.doFirst {
- println 'Hello Venus'
- }
- hello.doLast {
- println 'Hello Mars'
- }
- hello << {
- println 'Hello Jupiter'
- }
doFirst 和 doLast 可以进行多次调用。他们分别被添加在任务的开头和结尾。当任务开始执行时这些动作会按照既定顺序进行。
5、短标记法
每个任务都是一个脚本的属性,你可以访问它。
以属性的方式访问任务:
- task hello << {
- println 'Hello world!'
- }
- hello.doLast {
- println "Greetings from the $hello.name task."
- }
- // $hello.name 就是 “hello”
6、增加自定义属性
- task myTask {
- ext.myProperty = "myValue"
- }
-
- task printTaskProperties << {
- println myTask.myProperty
- }
7、调用 Ant 任务
Ant 任务是 Gradle 中的一等公民。Gradle 自带了一个 AntBuilder,可以通过它来调用一个 Ant 任务以及与 Ant 中的属性进行通信。
- task loadfile << {
- def files = file('../antLoadfileResources').listFiles().sort()
- files.each { File file ->
- if (file.isFile()) {
- ant.loadfile(srcFile: file, property: file.name)
- println " *** $file.name ***"
- println "${ant.properties[file.name]}"
- }
- }
- }
8、方法抽取
- task checksum << {
- fileList('../antLoadfileResources').each {File file ->
- ant.checksum(file: file, property: "cs_$file.name")
- println "$file.name Checksum: ${ant.properties["cs_$file.name"]}"
- }
- }
- task loadfile << {
- fileList('../antLoadfileResources').each {File file ->
- ant.loadfile(srcFile: file, property: file.name)
- println "I'm fond of $file.name"
- }
- }
- File[] fileList(String dir) {
- file(dir).listFiles({file -> file.isFile() } as FileFilter).sort()
- }
9、定义默认任务
- defaultTasks 'clean', 'run'
- task clean << {
- println 'Default Cleaning!'
- }
- task run << {
- println 'Default Running!'
- }
- task other << {
- println "I'm not a default task!"
- }
- $ gradle -q
- Default Cleaning!
- Default Running!
以上是一些 gradle 的基础小知识,下面以 android 项目为例,了解 gradle 实际是怎么工作的。