Java 强化

  • 代码规范(包、类、接口、方法、变量、常量名)
  • 主板加载通信组件案例(知识点回顾)
    • 面向接口编程 + 集合 + 匿名内部类
    • 加载资源文件 + 反射
  • JavaBean 规范
  • Lombok 工具(减少代码量)
  • 内省机制(Introspector)(重要)
  • apache的 commons 项目(了解)
    • JavaBean 和 Map 相互转换(自行实现)
    • commons-beanutils(了解、体验一下使用即可)
  • 注解(Annotation)
    • 初始注解
    • JDK自带的注解
    • 元注解(@Retention、@Target、@Documented、@Inherited)
    • 注解的定义和使用
    • 获取程序元素上的注解
    • 模拟 junit4.x

Java笔记目录可以点这里: Java强化笔记

代码规范(包、类、接口、方法、变量、常量名)

为什么要有编码规范(Why Have Code Conventions)?

  1. 一个软件的生命周期中,80%的花费在于维护;
  2. 几乎没有任何一个软件,在其整个生命周期中,均由最初的开发人员来维护;
  3. 编码规范可以改善软件的可读性,可以让程序员尽快而彻底地理解新的代码;
  4. 如果你将源码作为产品发布,就需要确任它是否被很好的打包并且清晰无误;
  5. 不规范,无高薪!

包名:标识符规范,全小写字母。

  • 域名倒写.模块名称.组件名;
  • com.wolfcode.crm.util;
  • cn.wolfcode._01_review;

类名:标识符规范,首字母大写,驼峰命名法,不要用拼音和拼音缩写。

  • Employee
  • EmployeeAdvancedSetting

接口名:副词、名词,习惯性以 I 开头。

  • IEmployeeDAO
  • IUSB

方法名:动词,首字母小写,驼峰表示法。

  • sayHello
  • saveEmployee

变量名:名词,首字母小写,驼峰表示法。

  • username
  • password
  • bornDate

常量名:全大写字母,单词之间使用下划线隔开。

  • MAX_VALUE
  • NOT_FOUND

主板加载通信组件案例(知识点回顾)

面向接口编程 + 集合 + 匿名内部类

声明一个 IUSB 接口作为规范:

// USB规范
public interface IUSB {void swapData();
}

创建一个实现该规范的类 Mouse

public class Mouse implements IUSB {public void swapData() {System.out.println("鼠标在移动");}
}

创建主板类 MotherBoard

import java.util.HashMap;
import java.util.Map;public class MotherBoard {// 存储安装的USB设备对象private Map<String, IUSB> plugins = new HashMap<>();// 将配件插在主板上public void install(String name, IUSB usb) {plugins.put(name, usb);}// 从主板上卸载指定的配件public void uninstall(String name) {plugins.remove(name);}// 主板通信, 让每个配件都工作public void doWork() {for (IUSB usb : plugins.values()) {usb.swapData();}}}

用来启动项目的类 App

public class App {public static void main(String[] args) {// 主板对象MotherBoard board = new MotherBoard();// 鼠标对象Mouse mouse = new Mouse();// 安装配件board.install("mouse", mouse);// 使用匿名内部类, 安装打印接对象board.install("print", new IUSB() {@Overridepublic void swapData() {System.out.println("打印......");}});// 调用主板的通信board.doWork();System.out.println("-----------------------");}
}
鼠标在移动
打印......
-----------------------

加载资源文件 + 反射

上面的一系列操作是很常规的面向接口编程,接下来重点来了!!!如果我们要添加一个键盘类 Keyboard要怎么做,新建一个 Keyboard 类,然后在 App.javanew 了,再进行操作吗?这样还是有点麻烦了,可以利用 加载资源文件 + 反射 真正实现解放双手。。

首先创建一个 资源文件夹(必须是 resource folder,它会在编译时将里面的文件放到项目的 path 路径),在里面引用 properties 文件:

# key = value
mouse = com.yusael._01_review.Mouse

此时目录是这样的:

来到 MotherBoard使用静态代码块加载资源文件,并通过反射创建对象

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;public class MotherBoard {// 存储安装的USB设备对象private static Map<String, IUSB> plugins = new HashMap<>();//-----------------------静态代码快加载资源文件-------------------------static {Properties p = new Properties();// 从classpath的根路径去加载plugins.properties文件try (InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("plugins.properties")){                       p.load(is);// 读取properties文件, 创建USB组件对象Set<Entry<Object, Object>> entrys = p.entrySet();for (Entry<Object, Object> entry : entrys) {// 资源文件中读取到的类名String className = entry.getValue().toString(); // 通过反射利用类名创建对象IUSB usbObject = (IUSB)Class.forName(className).newInstance();plugins.put(entry.getKey().toString(), usbObject);}} catch (Exception e) {e.printStackTrace();}}//-------------------------------------------------------------------// 将配件插在主板上public void install(String name, IUSB usb) {plugins.put(name, usb);}// 从主板上卸载指定的配件public void uninstall(String name) {plugins.remove(name);}// 主板通信, 让每个配件都工作public void doWork() {for (IUSB usb : plugins.values()) {usb.swapData();}}}

此时 APP 中的代码将变得十分简洁,我们无需再手动创建配件对象再调用主板的 install,我们只需要维护好配置文件 plugins.properties 中的内容即可。

比如,我们写一个键盘类 Keyboard

public class Keyboard implements IUSB{@Overridepublic void swapData() {System.out.println("键盘在跳舞");}
}

我们只需要将它添加到配置文件中即可。

# key=value
mouse = com.yusael._01_review.Mouse
keyboard = com.yusael._01_review.Keyboard

APP 中的代码是不需要动的。

public class App {public static void main(String[] args) {// 主板对象,MotherBoard board = new MotherBoard();// 调用主板的通信board.doWork();System.out.println("-----------------------");}
}
键盘在跳舞
鼠标在移动
-----------------------

JavaBean 规范

JavaBean 是一种JAVA语言写成的可重用组件(类),必须遵循一定的规范:

  1. 类必须使用 public 修饰
  2. 必须保证有公共无参数构造器
  3. 包含了属性的操作手段(gettersetter

分类:

  • 复杂:UI,比如 ButtonPanelWindow
  • 简单:domaindaoservice组件、封装数据、操作数据库、逻辑运算等

成员:

  • 方法:Method
  • 事件:event
  • 属性:property

属性:

  1. attribute:表示状态,Java中没有该概念,很多人把 字段(Field) 称之为 属性(attribute)
  2. property:表示状态,但是不是字段,是字段的操作方法(getter/setter)决定的

框架中使用的大多是是属性。

设置字段值:writeMethod: setter 方法:

public void setXxx(数据类型 变量){赋值操作;
}

若:setName ----> 属性:name
若:setUserName ----> 属性:userName
若:setISBN ----> 属性:ISBN

获取字段值:readMethod: getter方法:

public 数据类型 getXxx(){return 结果值;
}

若:getName ----> 属性:name
若:getUserName----> 属性:userName
若:getISBN ----> 属性:ISBN
若:数据类型是 boolean,则不叫 get 方法,而是is方法,如:isEmpty

标准的属性:一般提供字段,Eclipse 生成 getter/setter字段和属性同名

是否需要同时提供 getter/setter

public  class User{private String firstName;  // 名private String lastName; // 性别//在数据库只需要存储全名public void setFullName(String fullName){}
}

面试题:说说 JavaBean 和 EJB 的区别。

Lombok 工具(减少代码量)

一、Lombok 是什么
Lombok 是一款小巧的代码生成工具。官方网址:http://projectlombok.org/

Lombok 主要特性有:自动生成默认的 getter/setter 方法、自动化的资源管理(通过@Cleanup注解)及注解驱动的异常处理等。目前在国外广泛应用。

Lombok 它和 jquery 一样,目标是让程序员写更少的代码,以及改进一些原始语法中不尽人意的地方。Lombok 能做到这一点。既不是用 annotations process,也不是用反射。而是直接黑到了编译过程中。所以对运行效率没有任何影响,我们可以通过反编译 class 文件进行验证。

二、为何项目中要引入 Lombok

  1. 提高开发效率
  2. 使代码直观、简洁、明了、减少了大量冗余代码(一般可以节省60%-70%以上的代码)
  3. 极大减少了后期维护成本
  4. 修改变量名不需要再手动修改 getter/setter

三、使用 Lombok

  1. 给 Eclipse 安装插件,识别语法
  2. 在项目中引入 lombok 包
  3. 使用其中的注解(标签)

注意:构造器 和 toSring 也可以使用 lombok,但是建议写出来,看的更明显。

import lombok.Getter;
import lombok.Setter;@Getter@Setter
public class Person {private Long id;private String name;private Integer age;public Person(Long id, String name, Integer age) {this.id = id;this.name = name;this.age = age;}@Overridepublic String toString() {return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";}
}

Ctrl + O 可以看到当前类的字段方法getter/setter 已经存在。

内省机制(Introspector)(重要)

内省机制作用:查看和操作 JavaBean 中的属性

  • 获取 JavaBean 中的每一个属性名/属性类型
  • 通过 getter 方法获取属性值;通过 setter 方法给属性设置值

首先创建一个类 User

public class User {private String name;private int age;private boolean man;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public boolean isMan() {return man;}public void setMan(boolean man) {this.man = man;}}

下面是一个关于内省机制的例子:

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;// 内省机制: 操作User类值的属性
public class IntrospectorDemo {public static void main(String[] args) throws Exception {// 1:获取JavaBean的描述对象BeanInfo beanInfo = Introspector.getBeanInfo(User.class, Object.class);User u = User.class.newInstance();// 2:获取JavaBean中的属性的描述器PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();System.out.println(u); // 证明是同一个对象for (PropertyDescriptor pd : pds) {// 获取当前属性的名称System.out.println("属性名 = " + pd.getName());// 获取当前属性的getter方法System.out.println("getter : " + pd.getReadMethod());// 获取当前属性的setter方法System.out.println("setter : " + pd.getWriteMethod());System.out.println("--------------------------------");if ("name".equals(pd.getName())) {Method setter = pd.getWriteMethod(); // 获取方法setter.invoke(u, "Jack"); // 调用方法}}System.out.println(u);}
}

apache的 commons 项目(了解)

这部分内容了解一下就可以,知道 apache 有很多强大的项目,commons 是其中之一。

JavaBean 和 Map 相互转换(自行实现)

  • JavaBean 拥有多组属性名和属性值,每一个属性名称对应一个属性值,属性名称不同。
  • Map 拥有多组 key-value,每一个 key 对应一个 value,key 不同。

如果把 JavaBean 中的属性名称看做是 Map 中的 key,二者就是等价的。

把 JavaBean 转换为 Map 对象:

  • public static Map<String,Object> bean2map(Object bean){}

把Map对象转换为JavaBean:

  • public static Object map2bean(Map<String,Object> beanMap,Class beanType){}
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.Map;
import com.yusael._02_javabean.Person;// JavaBean的工具类
public class BeanUtil {public static void main(String[] args) throws Exception {Person p = new Person();p.setId(123L);p.setName("Jack");p.setAge(18);// JavaBean -> MapMap<String, Object> map = bean2map(p);System.out.println(map);// Map -> JavaBeanPerson obj = map2bean(map, Person.class);System.out.println(obj);}// 把JavaBean对象转换为Mappublic static Map<String, Object> bean2map(Object bean) throws Exception {Map<String, Object> map = new HashMap<>();BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class);PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();for (PropertyDescriptor pd : pds) {String name = pd.getName(); // 属性名称Object value = pd.getReadMethod().invoke(bean); // 调用getter方法, 获取属性值map.put(name, value);}return map;}// 把Map转换为JavaBeanpublic static <T> T map2bean(Map<String, Object> map, Class<T> beanType) throws Exception {// 创建JavaBean对象Object obj = beanType.newInstance();BeanInfo beanInfo = Introspector.getBeanInfo(beanType, Object.class);PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();for (PropertyDescriptor pd : pds) {// 从Map中获取和属性同名的key的值Object value = map.get(pd.getName());// 调用setter方法, 设置属性值pd.getWriteMethod().invoke(obj, value);}return (T)obj;}}

commons-beanutils(了解、体验一下使用即可)

这部分了解一下即可,大概体验一下这些工具类的作用。。。

需要 jar 包:commons-beanutils-1.9.4.jarcommons-logging-1.2.jar

import java.util.HashMap;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;
import com.yusael._02_javabean.Person;public class BeanUtilsDemo {public static void main(String[] args) throws Exception {Person p = new Person();Map<String, Object> map = new HashMap<>();map.put("id", "17210224");map.put("name", "Jack");map.put("age", "20");System.out.println(p);BeanUtils.copyProperties(p, map);System.out.println(p);}
}

转换时的一些细节:直接转换 long 类型的缺省值为 0,需注册为 Long,缺省值才为 null;


日期类转换的细节:beanutils 不支持 String --> Date 转换,需要手动设置转换模式。

注解(Annotation)

初始注解

Java5 开始,java 开始对元数据的支持,也就是 Annotation注解 / 标签

  • 元数据(metadata):描述数据的数据
  • 注解被用来为程序元素(类,方法,成员变量等)设置元数据。

所有的 Annotation 都是 java.lang.annotation.Annotation 接口的子接口

  • Annotation 是一种特殊的接口(好比枚举是特殊的类);
@interface Override {} ---> interface Override extends java.lang.annotation.Annotation{}

所有的枚举类,都是 java.lang.Enum 类的子类
enum Gender{} ---- > class Gender extends java.lang.Enum{}

使用注解需要注意,必须有三方参与才有意义:

  1. 得有注解标签;
  2. 被贴的程序元素(类、字段、构造器、方法等);
  3. 第三方的程序来赋予注解特殊的功能(也是Java代码);

JDK自带的注解

  • @Override:限定覆写父类方法
  • @Deprecated:标记已过时不推荐使用
    在 JDK1.5 之前,使用文档注释来标记过时
  • @SuppressWarings:抑制编译器发出的警告
    @SuppressWarings(value="all")
  • @SafeVarargs:抑制堆污染警告(Java7开始出现的)
    该注解仅仅是抑制住编译器不要报警告,但是存在的风险依然存在。

使用注解存在的疑惑:

  1. 为什么有的注解可以贴在类上/方法上/变量上,而有些却不行?
    肯定有东西来约束注解贴的位置。
  2. 为什么有的注解可以接受参数,比如@SuppressWarings(value="all"),而有的注解却不行。
    通过查看注解的源代码,发现注解中存在抽象方法才可以使用参数

元注解(@Retention、@Target、@Documented、@Inherited)

元注解:注解的元数据 —> 定义注解时,注解上的注解。

@Retention: 表示注解可以保存在哪一个时期;保存的时期的值,封装在 RetentionPolicy 枚举类中;一般自定义的注解,使用RUNTIME(使用反射赋予注解功能)

  • SOURCE:注解只能存在于源文件中,编译之后,字节码文件中没有。
  • CLASS: 注解可以存在于源文件和字节码文件中,无法加载进 JVM。
  • RUNTIME:注解可以存在于源文件,字节码文件,JVM 中。

@Target表示注解可以贴在哪些位置(类、方法、构造器上等等)
位置的常量封装在 ElementType 枚举类中:
* ElementType.ANNOTATION_TYPE:只能修饰 Annotation
* ElementType.CONSTRUCTOR:只能修饰构造方法
* ElementType.FIELD:只能修饰字段,包括枚举常量
* ElementType.LOCAL_VARIABLE:只能修饰局部变量
* ElementType.METHOD:只能修饰方法
* ElementType.PACKAGE:只能修饰(极少使用)
* ElementType.PARAMETER:只能修饰参数
* ElementType.TYPE:只能修饰类,接口,枚举

@Documented: 使用 @Documented 标注的标签会保存到API文档中

@Inherited: @Inherited 标注的标签可以被子类所继承

@Target(RetentionPolicy=RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@interface A{} // 定义一个 A标签
---------------------------------------
@A
class SuperClass{} // 使用 A标签
---------------------------------------
// SubClass 是 SuperClass 的子类
// 使用反射来检测 SubClass, 发现 SubClass 类上也有 A标签
// 说明 A标签 被继承了
class SubClass{}

注解的定义和使用

注解的定义语法:

@Target(ElementType.TYPE) // 标识该注解可以贴在类上/接口上
@Retention(RetentionPolicy.RUNTIME) // 标识该注解可以存在于JVM中(通过反射赋予功能)
public @interface 注解名称 {// 抽象方法-->属性返回类型 方法名称() default  值;...
}

注意:注解中 抽象方法(属性) 类型

  • 只能是 基本类型、StringClassannotation、枚举 、数组
  • 当只有一个属性并且名称为 value,此时可以省略 value
// @VIP(value="xx")
@VIP("xx") // 可以省略value
public class Employee {}

注解到底有什么用: 取代繁琐、臃肿的配置文件

  • 如果没有注解:
    学习 Servlet 做配置,需要在 XML 文件中写8行代码
  • 使用注解:
    学习 Servlet 的时候,只需要在 Servlet 类上标注:@WebServlet("/abc")

自定义一个注解 @VIP

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.TYPE) // 标识该注解可以贴在类上/接口上
@Retention(RetentionPolicy.RUNTIME) // 标识该注解可以存在于JVM中(通过反射赋予功能)
public @interface VIP {String value();int age() default 18; // 使用时可以省略, 默认值是18String [] hobby() default {"Python", "html"}; // 使用时可以省略
}

使用上面定义的 @VIP 注解:

// 注解中有default的是可以省略的
//@VIP(value="xx") 这么写相当于 @VIP(value="xx",age=18,hobby={"python,html"})
@VIP(value="xx",age=20,hobby={"Java","C++"})
public class Person {}

获取程序元素上的注解

注解可以贴在类(Class)、方法(Method)、字段(Field)、构造器(Constructor)上等;
所以在 ClassMethodFieldContructor 类中就拥有获取注解的API;

"如果存在该元素的指定类型的注解, 则返回这些注解, 否则返回 null"
Annotation  getAnnotation(Class annotationClass)
"返回此元素上存在的所有注解"
Annotation[] getAnnotations()
"判断当前成员上是否标注了某一个注解"
boolean isAnnotationPresent(Class annotationClass)

例:获取 Person上所有的注释;

例:判断 Person 类上是否有 @VIP 注解;

模拟 junit4.x

模拟 @Before 写一个 @MyBefore

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyBefore {}

模拟 @After 写一个 @MyAfter

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAfter {}

模拟 @Test 写一个 @MyTest

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {}

测试类:

public class PersonDAOTest {@MyBeforepublic void init() {System.out.println("初始化");}@MyAfterpublic void destory() {System.out.println("销毁");}@MyTestpublic void testSave() {System.out.println("测试保存");}@MyTestpublic void testDelete() {System.out.println("测试删除");}}

模拟编写测试代码:

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;public class JUnit5Mock {public static void main(String[] args) throws Exception {// 1):获取PersonDAOTest这份字节码对象Class clz = PersonDAOTest.class;Object obj = clz.newInstance(); // 测试类对象// 2):获取EmployeeDAOTest中所有的方法Method[] ms = clz.getMethods();// 3):迭代出每一个方法, 并判断每一个方法分别使用了什么注解, 并归类存储List<Method> beforeList = new ArrayList<>();List<Method> testList = new ArrayList<>();List<Method> afterList = new ArrayList<>();for (Method m : ms) {if (m.isAnnotationPresent(MyBefore.class)) {beforeList.add(m);} else if (m.isAnnotationPresent(MyAfter.class)) {afterList.add(m);} else if (m.isAnnotationPresent(MyTest.class)) {testList.add(m);}}// 4:循环迭代出testList中的每一个测试方法,并执行for (Method m : testList) {for (Method bm : beforeList) {bm.invoke(obj);}m.invoke(obj); // 运行测试方法for (Method am : afterList) {am.invoke(obj);}}}
}

执行测试,分别测试了保存删除

初始化
测试保存
销毁
初始化
测试删除
销毁

【Java 强化】代码规范、JavaBean、lombok、内省(Introspector)、commons 项目、注解详解相关推荐

  1. java游戏代码_Java与Kotlin系列文章之性能问题详解

    作者丨Jakub Anioła 译者丨姜雨生 策划丨田晓旭 随着对 Kotlin 越来越深入的了解,我发现市面上关于 Kotlin 方面,比较深入的资料几乎是 0,所以我决定,将 Kotlin 各个方 ...

  2. 代码规范七大原则_设计模式的七大原则详解||上篇

    Hello 丨World  当机会变得稀有,当竞争变得激烈 当方向不再清晰,当风口不再有风 关键词||设计模式 全文约7685字,细读大约需要20分钟 1 认识设计模式 1.1 什么是设计模式 所谓设 ...

  3. JAVA后端代码打包_Jenkins持续构建打包后端服务流程详解

    背景运用场景及思路 1.为响应后端开发人员需求,提升项目开发过程效率,选择Jenkins持续构建,进行导包启动一键持续集成 思路: 使用jenkins自带,立即构建->SVN拉取代码,通过Jen ...

  4. Java基础13:反射与注解详解

    Java基础13:反射与注解详解 什么是反射? 反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. Orac ...

  5. java method 注解_JAVA 注解详解及简单实例

    JAVA 注解详解及简单实例 何为注解 注解(Annotation)又称为元数据,在JDK1.5后引入,它的作用是: 生成文档  这是注解的原始用途,可以通过注解生成JavaDoc文档 跟踪代码的依赖 ...

  6. 【JAVA秘籍心法篇-Spring】Spring XML解析源码详解

    [JAVA秘籍心法篇-Spring]Spring XML解析源码详解 所谓天下武功,无坚不摧,唯快不破.但有又太极拳法以快制慢,以柔克刚.武功外式有拳打脚踢,刀剑棍棒,又有内功易筋经九阳神功.所有外功 ...

  7. 离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现

    [更新记录] 论文信息: David Brandfonbrener, William F. Whitney, Rajesh Ranganath, Joan Bruna: "Offline R ...

  8. java中北大学ppt总结+课后习题第二章(小宇特详解)

    java中北大学ppt总结+课后习题第二章(小宇特详解) 基本数据类型 Java语言有8种基本数据类型. 逻辑类型:boolean.1字节 整数类型: 1字节整数类型:byte. 2字节整数类型:sh ...

  9. 2022年Java面试总结,200多页真题笔记和详解(核心考点、6家大厂)

    为了进大厂,花了很多时间和精力在面试准备上,也刷了很多题.但题刷多了有点怀疑人生,不知道刷的这些题在之后的工作中能不能用到,如果只是为面试而刷题是不是在浪费人生呢? 如果你想进大厂,或者去一个更大.更 ...

最新文章

  1. 让学生网络相互学习,为什么深度相互学习优于传统蒸馏模型?| 论文精读
  2. Furein平台-比特币现金晋级毕竟在吵什么
  3. MongoDB导出csv格式数据
  4. MIGO相关的3个BADI增强点
  5. matlab delete、clf、cla、close、closereq删除对象
  6. dell服务器怎么看硬件状态,从DELL 2950和DELL R710看服务器硬件
  7. iscroll5实现一个下拉刷新上拉加载的效果
  8. Golang实践录:调用C++函数的优化
  9. linux 下rpm软件的安装和卸载
  10. ImageLoader的简单分析(终结篇)
  11. 战神CPU计算机硬件组装
  12. 服务器硬盘检测工具有哪些,最常用的10大服务器管理工具
  13. Badboy下载地址
  14. 复合查询sql子查询操作
  15. 微信们开放外链,互联网“圈地”成历史?
  16. 三维旋转详细解读(Rodrigues‘ Roatation Formula 罗德里格旋转公式)
  17. Android 中指纹识别的使用
  18. shiny 服务器未响应,在centos上重启shiny-server
  19. 基于BLM业务领先模型演化的项目管理四张地图
  20. 如何自建微信外卖平台_本地外面平台怎么起步,如何自建微信外卖平台

热门文章

  1. 大家对于晚上下班兼职滴滴司机有什么看法?
  2. 访问控制:protected
  3. 【Java开发规范】hashCode 和 equals 的处理规则
  4. Pytorch-张量的创建与使用方法
  5. linux内核根据skb获取目的mac地址
  6. Mybatis_day4_Mybatis的延迟加载
  7. dmv io读写高的sql_使用内置的动态管理视图(DMV)发现更多SQL Server信息
  8. hive join on 条件 与 where 条件区别
  9. win10 Docker Toolbox 默认路径不能写问题
  10. Hibernate api 之常见的类(配置类,会话工厂类,会话类)