一、类关系
继承、实现、依赖、组合、聚合
继承:一个类继承另一个类;
实现:一个类实现另一个接口;
依赖:一个类作为另一个的局部变量,方法的参数,临时对象等;
组合:一个类中使用了另一个类,如作为成员变量等属性,该类和类中的该成员变量生命周期一致;
聚合:一个类中使用了另一个类,如作为成员变量等属性,该类和类中的该成员变量生命周期不一致,二者可以分隔存在。
//继承
class ClassA extends Base{}
ClassA --|> Base
//实现
class ClassB implements ICallback{}
ClassB ..|> ICallback
//依赖
class Parm{}
class ClassC{
+doThings(Parm)
}
ClassC ..> Parm
//组合
class Combination{}
class ClassD{
Combination combination
}
ClassD *-- Combination
//聚合
class Polymerization{}
class ClassE{
Polymerization polymerization
}
ClassE o-- Polymerization
二、adb shell
adb shell下一些常用命令行工具:
pm:PackageManager,包管理器,用于管理应用程序的安装、卸载、查询和更多相关操作。
pm install …//
pm uninstall …//
pm list packages//设备上已安装的应用程序
pm dump …//获取应用程序的详细信息,如包名、版本号、权限等
pm list packages | grep **//查找与关键字相匹配的包名
adb shell dumpsys window/activity | findstr mCurrentFocus//查找当前应用界面的包名/活动名
logcat | grep … //查找与关键字想匹配的log
adb logcat > logcat.txt //将log输出到指定文件,若无该文件则先创建文件
am:Activity Manager,活动管理器,用于管理设备上的活动和应用程序的状态
am start …//
am stop …//
am force-stop …//
am broadcast //发送广播 adb shell am broadcast -a com.example.myapp.CUSTOM_ACTION --es message “Hello, World!” ——-a 参数指定广播的动作(Action),–es 参数用于添加一个额外的字符串值,键为 message,值为 “Hello, World!”
adb:Android 调试桥(Android Debug Bridge)是与 Android 设备通信的主要命令行工具。它提供了与设备进行文件传输、调试、安装应用程序和执行其他操作的功能。
ls:ls 命令用于列出目录中的文件和子目录。例如,ls /sdcard 可以列出设备存储卡(SD 卡)上的文件和目录。
cd:cd 命令用于更改当前工作目录。例如,cd /sdcard 可以将当前目录切换到设备存储卡。
mkdir:mkdir 命令用于创建新的目录。例如,mkdir /sdcard/new_directory 可以在设备存储卡上创建一个名为 “new_directory” 的新目录。
cp:cp 命令用于复制文件或目录。例如,cp /sdcard/file.txt /sdcard/backup/file.txt 可以将名为 “file.txt” 的文件复制到名为 “backup” 的目录下。
mv:mv 命令用于移动文件或目录,也可用于重命名文件或目录。例如,mv /sdcard/file.txt /sdcard/new_location/file_new.txt 可以将文件移动到新位置并重命名为 “file_new.txt”。
rm:rm 命令用于删除文件或目录。例如,rm /sdcard/file.txt 可以删除名为 “file.txt” 的文件,rm -f 删除文件夹目录
cat:cat 命令用于显示文件的内容。例如,cat /sdcard/file.txt 可以将文件的内容打印到命令行界面上。
chmod:chmod 命令用于更改文件或目录的权限。例如,chmod 755 /sdcard/file.txt 可以将文件的权限更改为 755。
三、json
解析json数据时可以使用GSON(Google提供的一个开源JSON库),Gson 可以将 Java 对象转换为 JSON 字符串,也可以将 JSON 字符串转换为 Java 对象。Gson 提供了更高级的功能和灵活性,例如支持自定义序列化和反序列化规则、处理复杂的对象关系、日期格式化等。
plugins {
id 'kotlin-parcelize'
}
依赖:
implementation "com.google.code.gson:gson:2.9.1"
序列化解析:
@Parcelize
class ParsingObject(
@SerializedName("event_code")//统一编码格式,将json里的下划线转化为驼峰格式
val eventCode: Int = 10501,
@SerializedName("event_code")
val eventValue: Int,
val event: String = "DEFAULT_VALUE",//默认值
val params: FlightParams
) : Parcelable
jsonString
val gson = Gson()
val obj = gson.formJson<ParsingObject>(jsonString, ParsingObject::class.java)
然后解析相应对象即可
json内容是一个list
val info = gson.fromJson(jsonString, Array<ParsingObject>::class.java).toList()
当json内有pair对时,pair对数量未知,且value类型未知
"params":{
"key1":20,
"key2":"value",
"key3":true
}
@Parcelize
class ParseObject(val params : Map<String, @RawValue Any>) : Parcelable
jsonObject解析:
//根据相应特征字段名获取
val jsonObject = JSONObject(jsonStr)
val jsonArray = jsonObject.getJSONArray("list")
val obj = jsonArray.getJSONObject(0)
val cityObj = obj.getJSONObject("cityInfo")
四、java spi
核心思想:解耦
SPI(Service Provider Interface),是JDK内置的一种 服务提供发现机制,可以用来启用框架扩展和替换组件。
1.定义接口及其实现类
public interface IFather{...}
public class Son implements IFather{...}
2.在resources目录下新建META-INF/services目录
在services目录下新建文件,文件名为接口类的目录,文件内容为要实现的类。
文件名:com.example.IFather
文件内容:com.example.Son
3.加载
ServiceLoader<IFather> s = ServiceLoader.load(IFather.class);
Iterator<IFather> it = s.iterator();
while(it.hasNext()) {
IFather c = it.next();
...
}
4.实现类必须携带一个不带参数的构造函数
五、Annotation
1 个 Annotation 和 1 个 RetentionPolicy 关联。
1 个 Annotation 和 1~n 个 ElementType 关联。
Annotation 有许多实现类,包括:Deprecated, Documented, Inherited, Override 等等
package java.lang.annotation;
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
package java.lang.annotation;
public enum ElementType {
TYPE, /* 类、接口(包括注释类型)或枚举声明 */
FIELD, /* 字段声明(包括枚举常量) */
METHOD, /* 方法声明 */
PARAMETER, /* 参数声明 */
CONSTRUCTOR, /* 构造方法声明 */
LOCAL_VARIABLE, /* 局部变量声明 */
ANNOTATION_TYPE, /* 注释类型声明 */
PACKAGE /* 包声明 */
}
@Target(ElementType.Type)//若有就表示用于指定的地方,若无则表示可用于任何地方
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE, /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了 */
CLASS, /* 编译器将Annotation存储于类对应的.class文件中。默认行为 */
RUNTIME /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
}
@Retention(RetentionPolicy.RUNTIME)//没有RetentionPolicy默认是CLASS
@Deprecated -- @Deprecated 所标注内容,不再被建议使用。
@Override -- @Override 只能标注方法,表示该方法覆盖父类中的方法。
@Documented -- @Documented 所标注内容,可以出现在javadoc中。
@Inherited -- @Inherited只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性。
@Retention -- @Retention只能被用来标注“Annotation类型”,而且它被用来指定Annotation的RetentionPolicy属性。
@Target -- @Target只能被用来标注“Annotation类型”,而且它被用来指定Annotation的ElementType属性。
@SuppressWarnings -- @SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。
一个示例:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface ServiceFunctionParameters {
String NO_DEFAULT_VALUE = "ServiceFunctionParameters_NO_INPUT_PROVIDED";
String description() default "";
String name();
String defaultValue() default NO_DEFAULT_VALUE;
boolean required() default true;
Class<?> type() default String.class;
}
fun addCalendarSchedule(
@ServiceFunctionParameters(
name = "title",
description = "你需要根据该日程主题给拟一个标题"
) title: String?,
@ServiceFunctionParameters(
name = "description",
description = "日程的具体内容"
) description: String?,
@ServiceFunctionParameters(
name = "startTime",
description = "日程开始时间,格式:yyyy-MM-dd HH:mm:ss"
) startTime: String?,
@ServiceFunctionParameters(
name = "endTime",
description = "日程结束时间,格式:yyyy-MM-dd HH:mm:ss"
) endTime: String?,
) {...}
六、泛型
1.泛型方法
所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前。
每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像 int、double、char 等)。
public class GenericMethod {
//泛型方法
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( "整型数组元素为:" );
printArray( intArray ); // 传递一个整型数组
System.out.println( "\n双精度型数组元素为:" );
printArray( doubleArray ); // 传递一个双精度型数组
System.out.println( "\n字符型数组元素为:" );
printArray( charArray ); // 传递一个字符型数组
}
}
整型数组元素为:
1 2 3 4 5
双精度型数组元素为:
1.1 2.2 3.3 4.4
字符型数组元素为:
H E L L O
2.泛型类
泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分,和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符,因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
stringBox.add(new String("测试"));
System.out.printf("整型值为 :%d\n\n", integerBox.get());//整型值为 :10
System.out.printf("字符串为 :%s\n", stringBox.get());//字符串为 :测试
}
}
3.类型通配符
类型通配符一般是使用 ? 代替具体的类型参数
import java.util.*;
public class GenericTest {
public static void main(String[] args) {
List<String> name = new ArrayList<String>();
List<Integer> age = new ArrayList<Integer>();
List<Number> number = new ArrayList<Number>();
name.add("icon");
age.add(18);
number.add(314);
getData(name);//data :icon
getData(age);//data :18
getData(number);//data :314
}
public static void getData(List<?> data) {
System.out.println("data :" + data.get(0));
}
}
类型通配符的下限由 ? extends Class定义,即只能为Class或其子类
import java.util.*;
public class GenericTest {
public static void main(String[] args) {
List<String> name = new ArrayList<String>();
List<Integer> age = new ArrayList<Integer>();
List<Number> number = new ArrayList<Number>();
name.add("icon");
age.add(18);
number.add(314);
//getUperNumber(name);//String非Number的子类
getUperNumber(age);//
getUperNumber(number);//
}
public static void getUperNumber(List<? extends Number> data) {
System.out.println("data :" + data.get(0));
}
}
类型通配符的上限由 ? super Class定义,即只能为Class及其上层父类型,如object
七、Mono响应式编程
异步编程,处理耗时逻辑。mono用于处理包含零个或一个元素的异步序列。
val mono = Mono.fromCallable{
......//耗时逻辑
}
mono.subscribe{result ->
Log.d(TAG,"....")
}//只有subscribe这里订阅了,fromCallable里的耗时逻辑才会执行
val mono = Mono.just{
...
}
同样需要订阅
//让耗时逻辑在子线程中执行
mono.subscribeOn(Schedulers.Parallel())
mono.subscribeOn(Schedulers.boundedElastic())
八、正则表达式
正则表达式定义了字符串的模式,可以用来搜索、编辑或处理文本。
java.util.regex包主要包括以下三个类:
1.Pattern类:Pattern对象是一个正则表达式的编译表示,没有公共构造方法,通过调用公共静态编译(compile)方法返回其对象,该方法接受一个正则表达式作为它的第一个参数。
2.Matcher类:Matcher对象是对输入字符串进行解释和匹配操作的引擎,没有公共构造方法,需要调用Pattern对象的matcher方法获得一个Matcher对象。
3.PatternSyntaxException类:一个非强制异常类,表示一个正则表达式模式中的语法错误。
Matcher类的一些方法:
int start():匹配的初始索引
int end():匹配字符之后的偏移量
boolean lookingAt():从字符串头开始是否有与之匹配的子序列
boolean matches():整个字符串是否与之匹配
boolean find():查找与该模式匹配的输入序列的下一个子序列
String replaceAll(String):将匹配的子序列与全部替换
String replaceFirst(String):替换第一个
Matcher appendReplacement(StringBuffer,String):非终端添加和替换
StringBuffer appendTail(StringBuffer):终端添加和替换
Java通过Pattern对象和Matcher对象实现正则匹配功能,Pattern负责编译正则表达式、Matcher类负责匹配操作。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches
{
private static final String REGEX = "foo";
private static final String INPUT1 = "fooooooooooooooooo";
private static final String INPUT2 = "ooooofoooooooooooo";
private static Pattern pattern;
private static Matcher matcher1;
private static Matcher matcher2;
public static void main( String[] args ){
pattern = Pattern.compile(REGEX);
matcher1 = pattern.matcher(INPUT1);
matcher2 = pattern.matcher(INPUT2);
System.out.println("lookingAt(): "+matcher1.lookingAt());//true
System.out.println("matches(): "+matcher1.matches());//false
System.out.println("lookingAt(): "+matcher2.lookingAt());//false
}
}
public class RegexMatches
{
private static String REGEX = "a*b";
private static String INPUT = "aabfooaabfooabfoobkkk";
private static String REPLACE = "-";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT);
StringBuffer sb = new StringBuffer();
while(m.find()){
m.appendReplacement(sb,REPLACE);
}
m.appendTail(sb);//sb:-foo-foo-foo-kkk
}
}
Kotlin中Regex负责将字符串转化为正则表达式,然后调用匹配函数进行匹配
val curIndex = (Regex("""\d+""").find(plan)?.value?.toInt() ?: 0)//匹配plan字符串plan中的数字
val input = "Hello, this is a sample text with some numbers like 12345 and 67890."
val regex = "\\d+".toRegex() // 匹配数字
val matches = regex.findAll(input)
九、异步代码顺序执行
多个线程异步执行时使多个线程按照先后顺序同步执行。
1.通过join方式
val thread1 = Thread {
Log.d("111111", "111111")
}
val thread2 = Thread {
Log.d("111111", "222222")
}
val thread3 = Thread {
Log.d("111111", "333333")
}
thread1.start()
thread1.join()
thread2.start()
thread2.join()
thread3.start()
thread3.join()
2.通过线程池
val thread1 = Thread {
Log.d("111111", "111111")
}
val thread2 = Thread {
Log.d("111111", "222222")
}
val thread3 = Thread {
Log.d("111111", "333333")
}
val executor = Executors.newSingleThreadExecutor()//创建单个线程的线程池
executor.submit(thread1)
executor.submit(thread2)
executor.submit(thread3)
executor.shutdown()//关闭
创建几种不同的线程池:
**固定大小的线程池**
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(new MyTask());
executor.shutDown();//发生关闭请求,待所有任务执行完毕则关闭线程池。
List<Runnable> remainingTasks = executor.shutdownNow(); //立即关闭线程池并返回未执行的任务列表
**可缓存的线程池**
根据需要创建新线程的线程池,有新任务时有空余线程则启用,无可用线程则创建新的线程,当线程处于空闲状态超过指定时间(默认为 60 秒),则会被终止并移出线程池。
Executor executor = Executors.newCachedThreadPool();
// 提交 10 个任务给线程池执行
for (int i = 0; i < 10; i++) {
final int taskId = i;
// 创建一个具名的 Runnable 对象表示每个任务
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("Executing task " + taskId + " on thread " + Thread.currentThread().getName());
}
};
executor.submit(task);
}
// 关闭线程池
executor.shutdown();
**定时执行任务的线程池**
// 创建一个大小为 2 的定时执行任务的线程池
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2);
// 延迟 1 秒后执行任务
executor.schedule(() -> {
System.out.println("Task 1 executed after 1 second");
}, 1, TimeUnit.SECONDS);
// 延迟 2 秒后开始执行任务,之后每隔 3 秒执行一次
executor.scheduleAtFixedRate(() -> {
System.out.println("Task 2 executed at fixed rate of 3 seconds");
}, 2, 3, TimeUnit.SECONDS);
// 关闭线程池
executor.shutdown();
**自定义的线程池**
// 创建一个自定义线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // 核心线程数
4, // 最大线程数
10, // 空闲线程存活时间
TimeUnit.SECONDS, // 存活时间的单位
new ArrayBlockingQueue<>(2) // 任务队列
);
// 提交任务
for (int i = 0; i < 6; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " executed by " + Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
// 关闭线程池
executor.shutdown();
十、多线程
继承类的方式实现多线程
//kotlin
class MyThread : Thread() {
override fun run() {...}
}
class MyRunnable : Runnable {
override fun run() {...}
}
//java
class MyThread extends Thread() {
public void run() {...}
}
class MyRunnable implements Runnable {
public void run() {...}
}
匿名类的方式
//kotlin
Thread {
...
}.start()//java函数式api
//java
Thread thread = new Thread(new Runnable() {
public void run() {...}
});
thread.start()
//lambda表达式
Thread thread = new Thread(() -> {
...
});
thread.start()
十一、锁-synchroized
方法加锁:
在Java中,synchronized关键字用于创建同步块或同步方法,用于实现多线程之间的同步操作,避免多个线程同时访问共享资源而导致的数据不一致或并发问题。当使用synchronized关键字时,最终被锁住的是对象实例或类,具体取决于是在实例方法上还是静态方法上使用synchronized。
实例方法上的synchronized:
当在实例方法上使用synchronized关键字时,最终被锁住的是对象实例,即对应的this引用。每个对象实例都有自己的锁,因此同一个类的不同实例之间的synchronized方法调用是互相独立的,不会相互阻塞。
public synchronized void someMethod() {
// 代码块
}
静态方法上的synchronized:
当在静态方法上使用synchronized关键字时,最终被锁住的是类的Class对象,即类级别的锁。这意味着无论类的实例个数多少,所有实例共享同一个锁。
public static synchronized void someStaticMethod() {
// 代码块
}
无论是实例方法还是静态方法,synchronized都会锁住对应的对象实例或类的Class对象,从而确保在同步块中的代码只能被一个线程执行,避免了多线程访问共享资源时可能出现的并发问题。
方法块内部的锁:
object是同步的一个信物,object的变量属性等在其他线程皆可以被访问。当其他线程使用object作为同步信物时,只有当获取了object的锁之后,其同步块内的逻辑才能被执行。
Object object = new Object();
public void getValue(){
synchroized(object){
//同步块
}
}
十三、Windows系统CMake新手入门级简单使用
1.CMakeList.txt
#CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
#项目信息
project (CMakeDemo)
#指定生成目标+需构建的文件
add_executable(Demo test.cpp)
2.CMake使用
mkdir build//新建build目录存放构建生成的文件
cd build
cmake …//
cmake --build .//生成debug版本的执行文件
cmake --build . --config Release//生成release版本的执行文件
3.使用生成的文件
使用Windows命令行窗口运行:
在Demo.exe目录下运行命令行窗口,输入:Demo.exe即可执行,如果需要参数的话输入Demo.exe parm1 parm2 …即可执行。
十四、Java反射
反射:通过Class实例获取class信息的方法称为反射,
Class实例:保存了某个class的所有信息。如果获取了某个Class实例,就能获取其对应的class的所有信息。Class实例在JVM中唯一。
获取一个class的Class实例方法(以String为例):
1——Class cls = String.class
2——String s = “Hello”
Class cls = s.getClass()
3——Class cls = Class.forName(“java.lang.String”)//知道一个class的完整类名
1.访问字段Field
Field getField(name)//根据字段获取某个public的field(包括父类)
Field getDeclaredField(name)//根据字段获取当前类的某个field(不包括父类)
Field getFields()//获取所有public的field(包括父类)
Field getDeclaredFields()//获取当前类的所有field(不包括父类)
——调用对象为Class
Class stdClass = Student.class;//Student为一个类
// 获取public字段"score":
System.out.println(stdClass.getField("score"));
// 获取继承的public字段"name":
System.out.println(stdClass.getField("name"));
getName():返回字段名称,例如,“name”;
getType():返回字段类型,也是一个Class实例,例如,String.class;
getModifiers():返回字段的修饰符,它是一个int,不同的bit表示不同的含义。
——调用对象为Field
Field.get(Object)//获取某个字段的值
Field.set(ObjectA,ObjectB)//设置ObjectA的值为ObjectB
Field.setAccessible(true)//设置某个字段可访问,可能返回false
public class Test {
public static void main(String[] args) throws Exception {
Object p = new Person("Jack");//new 对象
Class c = p.getClass();//获取Class
Field f = c.getDeclaredField("name");//获取Field
f.setAccessible(true);//设备可访问
Object value = f.get(p);//获取值
}
}
class Person {
private String name;
public Person(String name) {
this.name = name;
}
}
2.访问方法Method
Method getMethod(name, Class)//获取某个public的Method(包括父类),后面的Class为该方法的参数
Method getDeclaredMethod(name,Class)//获取当前类的某个Method(不包括父类)
Method[] getMethods()//获取所有public的Method
Method[] getDeclaredMethods()//获取当前类的所有Method
——调用对象为Class
getName():返回方法名称,例如:“getScore”;
getReturnType():返回方法返回值类型,也是一个Class实例,例如:String.class;
getParameterTypes():返回方法的参数类型,是一个Class数组,例如:{String.class, int.class};
getModifiers():返回方法的修饰符,它是一个int,不同的bit表示不同的含义。
——调用对象为Method
对Method实例调用invoke就相当于调用该方法,invoke的第一个参数是对象实例,后面的可变参数要与方法参数一致,如果方法为静态方法,第一个参数为null。
Method.setAccessible(true)//设置某个字段可访问,可能返回false
public class Test {
public static void main(String[] args) throws Exception {
Person p = new Person();
Method m = p.getClass().getDeclaredMethod("setName", String.class);//获取Method
m.setAccessible(true);//设置可访问
m.invoke(p, "Jack");//调用方法
}
}
class Person {
String mName;
private void setName(String name) {
mName = name;
}
}
十五、可变参数
1.java
public void printStrings(String... strings) {
for(String str : strings) {
...
}
}
2.kotlin
使用关键字vararg
fun printString(vararg strings: String) {
for(str in strings) {
...
}
}
3.C
#include <stdio.h>
#include <stdarg.h>
void printNumbers(int num, ...) {
va_list args;
va_start(args, num);
for(int i=0;i<num;i++){
int value = va_args(args,int)
}
va_end(args)
}