Java 基础回顾-1:基本知识总结

给跨代引用记一本账:Java GC 的分配路径、卡表写屏障与收集器版图快速回顾 本文把 Java GC 的零散名词串成一条推理链路:从 TLAB 指针碰撞分配、逃逸分析,到 Eden、Survivor 与晋升的四条路,重点拆解卡表与写屏障如何为老年代指向新生代的引用记账,及 Minor GC 如何只扫脏卡。基于 JDK 8 实测:分散写使 Young GC 停顿涨 10~15 倍,条件卡标记消除卡表伪共享,计数循环让 System.gc 等待 2.7 秒,Survivor 过小使晋升量增加约 400 倍。文末梳理 JDK 8 到 27 的收集器演进、选型路径与排查顺序。 阅读详情

本篇文章对 Java 中的语言相关的基础知识进行了总结,其中部分内容参考了阿里的 Java 开发规范

1、术语

No结论
1JDK 是编写Java程序的程序员使用的软件
2JRE 是运行Java程序的用户使用的软件
3Java的执行模式是编译和解释型,Java程序首先由编译器转换为标准字节代码,然后由JVM来解释执行,JVM将字节代码程序同操作系统和硬件分开,使Java程序独立于平台运行
4垃圾回收机制是一个系统线程,对内存使用进行跟踪
5Class 类对象由 Java 编译器自动生成,隐藏在 .class 文件中
6JVM 运行 Java 代码的步骤: 装载-链接-初始化(运行时不需要加载代码)
7动态绑定: 在运行时能够自动地选择调用哪个方法的现象
8Jar 是一种压缩的文件,使用了 ZIP 格式,其中包含一个清单文件 MANIFEST.MF 位于 META-INF 目录
9JavaScript 是网页中使用的脚本语言,语法类似于Java,除此之外无任何联系
10Java 大小写敏感

2、Java程序的基本结构

程序结构

	package me.shouheng;
	
	import java.util.ArrayList;
	import java.util.List;
	
	public class Test {
	    public static void main(String ...args) {
	        System.out.println("Hello world!");
	        List<String> s = new ArrayList<String>();
	    }
	}

简单说明:

No说明
1main 方法用于控制程序的开始和结束,main 方法包含以下要素:public、static、void 和 String[] args
2可以使用 new 关键字创建类的实例对象,可以直接通过类名调用类所提供的静态成员

包

No说明
1包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用单数形式,但是类名如果有复数含义,类名可以使用复数形式。【规范】
2package 语句必须是源程序文件中第一个非注释、非空白语句
3包的成员可以包含子包、类、接口。如果源代码中没有指定包,则使用默认包
4一个包(子包)的成员不能重名,即使不同的类型

包的访问方式:

  1. 完全限定名称方式访问:java.net.InetAddress hostAdd
  2. 导入包成员:import java.net.InetAddress
  3. 导入整个包:import java.net.*
  4. 导入类的静态成员:import static java.lang.Math.*
  5. 访问包成员名称冲突:需要使用完全限定名称方式

3、标识符

由字符、数字、下划线、美元符号($)组成,且开头不能为数字,分大小写,没有长度限制,不能与关键字相同. 约定如下

No元素约定
1包常用名词,全部小写
2类、接口常用名词,每个单词首字母大写;(PascalCase规则)
3方法常用动词,首字母小写;(camelCase规则)
4常量常用名词,全部大写,单词之间用下划线(_)分隔
5变量成员名称,首字母小写. (camelCase规则)

规范:

No规范
1【强制】代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束
2【强制】代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式
3【强制】类名使用 UpperCamelCase 风格,必须遵从驼峰形式,但以下情形例外:DO/BO/DTO/VO/AO
4【强制】常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长
5【强制】抽象类命名使用Abstract或Base开头;异常类命名使用Exception结尾;测试类命名以它要测试的类的名称开始,以Test结尾
6【强制】POJO 类中布尔类型的变量,都不要加is ,否则部分框架解析会引起序列化错误
7【推荐】如果使用到了设计模式,建议在类名中体现出具体模式
8【推荐】 如果是形容能力的接口名称,取对应的形容词做接口名( 通常是–able的形式)
9【强制】对于 Service 和 DAO 类,基于 SOA 的理念,暴露出来的服务一定是接口,内部的实现类用 Impl 的后缀与接口区别

此外,Service / DAO 层方法命名规约

  1. 获取单个对象的方法用 get 做前缀。
  2. 获取多个对象的方法用 list 做前缀。
  3. 获取统计值的方法用 count 做前缀。
  4. 插入的方法用 save( 推荐 ) 或 insert 做前缀。
  5. 删除的方法用 remove( 推荐 ) 或 delete 做前缀。
  6. 修改的方法用 update 做前缀。

4、程序流程

4.1 基本程序结构

  1. 顺序结构
  2. 选择结构:if 语句和 switch 语句
  3. 循环结构:for 循环、while 循环、do...while 循环、for each 循环
  4. 跳转语句:break 语句、continue 语句、return 语句
两个需要注意的地方
  1. 在 Java 中 for each 循环体语句序列中,数组或集合的元素是只读的,其值不能改变,若要改变可用常规 for 循环.
  2. 应该强制在使用 for 循环的时候加上 {}。下面的程序示例:

假如有一段程序:

    for (int i=0;i<10;i++) int k = 5;
    for (int i=0;i<10;i++) {int k = 5;}

上面的两种写法:第一种是错误的,for 循环可以不加 {},但是那仅限于执行语句,不能包含变量声明语句。第一段代码定义了 k,它的作用域是包含 for 循环的整个方法,因此会造成重复定义的编译错误。

foreach

foreach 循环使用了迭代器设计模式,它的基本使用方法:如果想要自己的数据集合能够使用 foreach 的方式遍历集合的元素,那么我们需要自己的容器实现 Iterable 接口。下面是在为背包变成可迭代的列子:

	public class Bag<E> implements Iterable<E> {
	    private Node<E> first;
	
	    private static class Node<E> {
	        E element;
	        Node<E> next;

	        Node(E element, Node<E> next) {
	            this.element = element;
	            this.next = next;
	        }
	    }
	
	    public void add(E element) {
	        first = new Node<E>(element, first);
	    }
	
	    public Iterator<E> iterator() {
	        return new ListIterator();
	    }
	
	    private class ListIterator implements Iterator<E> {
	        private Node<E> current = first;
	
	        @Override
	        public boolean hasNext() {
	            return current != null;
	        }
	
	        @Override
	        public E next() {
	            E element = current.element;
	            current = current.next;
	            return element;
	        }
	
	        @Override
	        public void remove() {}
	    }
	}

4.2 异常控制结构

异常为我们提供了一种解决问题的机制,有了它我们就可以实现将业务逻辑和异常处理相分离,从而使我们的代码更加易于维护和理解。

Java 异常的结构层次

Java异常的结构层次

  1. 所有的异常类是从 java.lang.Exception 类继承的子类;
  2. Exception 类是 Throwable 类的子类。除了 Exception 类外,Throwable 还有一个子类 Error,用来指示运行时环境发生的错误,我们最好不要在程序中定义 Error 的子类;
  3. Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在 Java 程序处理的范畴之外;
  4. 异常类有两个主要的子类:IOException 类和 RuntimeException 类;
  5. Java 提供了三种可抛出结构:受检异常、运行时异常和错误;
  6. 每个抛出的异常都要有文档。

对于使用受检的异常还是未受检的异常的原则:对于可恢复的情况,使用受检的异常;对于程序错误,使用运行时异常。

运行时异常(可以参考上图)通常意味着程序不符合API规范,继续运行下去也无济于事。而受检异常则意味着,对出现了异常进行正确的处理之后,程序仍然能够继续执行。
不过这只是一种规范,但实际上不论运行时异常还是受检异常都是可以捕获并处理的。

异常处理程序的结构
    try {
        int k = 1/0;
    } catch (ArithmeticException e) {
        e.printStackTrace();
    } finally {
        System.out.println("finally");
    }
  1. 异常处理系统会按照“就近”原则匹配异常,如果满足了匹配就不再继续向下匹配。因此,在 catch 语句中捕获异常的时候,要按照从子类到基类的顺序捕获(从具体错误到顶层错误)。
  2. 异常链返回:finally 语句总是会执行,所以在一个方法中可以从多个点返回,却仍然能够保证清理工作的进行。

一个异常终止的示例程序:

    public static void main(String ...args) {
        for (int i=1; i>=0; i--) {
            System.out.println(f(i));;
        }
    }

    private static int f(int i) {
        try {
            int k = 1 / i;
            return 0;
        } catch (ArithmeticException e) {
            System.out.println("catch");
            return 1;
        } finally {
            try {
                Thread.sleep(1000);
                System.out.println("finally");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

以上程序的输出结果是:

	finally
	0
	catch
	finally
	1

可见,finally 总是会被调用,而且 return 语句要等待 finally 执行完毕才会调用。

异常使用指南

建议使用异常的情况:

  1. 异常应该只用于异常的情况;它们永远不应该用于控制正常的控制流。
  2. 如果在 try 语句块中已经出现了异常,而我们在 finally 语句块中进行异常处理的时候又抛出了异常,或者使用了 return 语句,那么这个时候我们的第一个抛出的异常会丢失。
    丢失的后果就是当程序出现了错误的时候,我们没有办法对错误发生的位置进行定位。
  3. 在恰当的级别处理问题(知道该如何处理的情况下捕获异常);
  4. 解决问题并且重新调用产生异常的方法;
  5. 进行少许修补,然后绕过异常发生的地方继续执行;
  6. 用别的数据进行计算,以代替方法预计会返回的值;
  7. 把当前运行环境下能做的事情尽量做完,然后把相同的异常抛到高层;
  8. 把当前运行环境下能做的事情尽量做完,然后把不同的异常抛到高层;
  9. 终止程序;
  10. 进行简化;
  11. 让类库和程序更安全。

5、运算符

5.1 运算符(基本同C,特别说明几个)

No运算符说明
1自增(++)/自减(--)运算符注意它本质上是分3步执行的(所以非原子的),运算符放在前面和后面会有区别
2算术运算符(+、-、*、/)当参与 / 运算的两个操作数都是表示整数除法,否则是浮点数除法
3比较运输符(>、<、>=、<=、!=、==)参考总结1
4字符串运算符(+)运算符用于串联两个字符串,对非字符串类型的通过调用从Object类继承的toString()方法将其转换为字符串形式
5赋值运算符(+= -= *= /= %= <<= >>= &= &#124;= ^=)要求右边的操作数可以隐式地转换为左边的操作数或类型相同

5.2 总结1:关于比较运算符

No总结
1形如 a<b<c 的复合比较式要写成 (a<b)&&(b<c) 而不能是 a<b<c
2简单数据类型比较的是它的值
3引用类型比较的是两个引用是否指向同一对象实例,即是否指向同一内存位置
4引用类型的比较中,参与比较的两个引用类型必须能够转换为同一引用类型
5null 常量表示非空对象,可以与任何引用类型变量比较
6如果参与比较的两个操作数,一个为常量,则采用值比较方式,而非引用地址
7引用类型的比较可以使用对应类的 equals(Object obj) 方法实现
8比较运算符具有截断性,如果前面的能够得出表达式的结果就不再继续比较了,比如 if(obj != null && ebj.equals(obj2)),这里如果 ebj 是 null 的话是不会进行 equals 比较的
9equals() 方法默认比较引用,要想实现自己的比较逻辑必须覆写该方法。同时要注意 equals() 和 hashCode() 方法需要同时覆写
10对浮点数的比较是非常严格的,即使一个数仅在小数部分与另一个数存在极微小的差异,仍然认为它们是不相等的。即使一个数比零大一点点,它仍然是非零的值

5.3 总结2:关于字符串运算符

  1. 错误的例子 String s0 = true + false + “abc”; // 错误(true+false)运算错误
  2. 对于字符串,+ 运算是每次创建一个 StringBuilder 对象,并调用它的 append 方法添加字符串,所以使用StringBuilder 比使用 + 的效率更高

5.4 总结3:关于移位

>> 和 >>> 的区别:

    System.out.println(Integer.toBinaryString(Integer.MAX_VALUE));         // 输出结果:1111111111111111111111111111111
	System.out.println(Integer.toBinaryString(Integer.MAX_VALUE >> 10));   // 输出结果:111111111111111111111
    System.out.println(Integer.toBinaryString(Integer.MAX_VALUE >>> 10));  // 输出结果:111111111111111111111
    System.out.println(Integer.toBinaryString(-1));                        // 输出结果:11111111111111111111111111111111
    System.out.println(Integer.toBinaryString(-1 >> 10));                  // 输出结果:11111111111111111111111111111111
    System.out.println(Integer.toBinaryString(-1 >>> 10));                 // 输出结果:1111111111111111111111
    System.out.println(-1 >> 1);                                           // 输出结果:-1
    System.out.println(-1 >>> 1);                                          // 输出结果:4194303
  1. 32>>32 相当于 32>>0,而 32>>33 相当于32>>1;
  2. 左移 (<<) 能按照操作符左侧指定的位数将操作符左边的操作数向左移动(在低位补0);
  3. “有符号”右移操作符(>>)按照操作符右侧指定的位数将从操作符左边的操作数向右移动;
  4. “有符号”右移操作符使用 “符号拓展”:若符号位为证,则在高位插入0,若符号位为负,则在高位插入1;
  5. “无符号”右移操作符(>>>),无论正负都在高位插入0.

5.5 问题

5.5.1 问题1:以下程序的输出结果是?
    int j = 0;
    for (int i = 0; i < 100; i++) {
        j = j++;
    }
    System.out.println(j);

输出结果是 0,这是因为 j=j++ 操作等价于 int temp=j; j=j+1; j=temp;

5.5.2 问题2: 以下两个表达式,哪个正确?
    short s = 1; s = s + 1;
    short s = 1; s += 1;

第二个,因为 s+1 为 int 型,不能赋值给 short 类型。第二个表达式中会被强制转型为 short 类型。

5.5.3 问题3:以下程序的输出结果是
    char x = 'x';
    int i = 10;
    System.out.println(false ? i : x);
    System.out.println(false ? 10 : x);

120 和 x,这是因为第一个输出中,i 为 int 类型,第一个输出被提升为 int 型;第二个输出中,10 是常量,常量 10 可以被 char 表示,故输出 char 型。

6、基本数据类型

  1. Java中的数据类型分成:引用类型和简单类型 两个大类;
  2. 引用类型包括:类、接口、数组和 null 类型;
  3. 简单类型包括:数值类型和布尔类型。

6.1 整数

6.1.1 取值范围

Java 中整型的范围与运行 Java 的机器无关。它只有有符号的整数,没有无符号的。下面是它们的范围:

数据类型字节范围
byte1 字节-128 ~ 127
short2 字节-32768 ~ 32767 (正负3万)
int4 字节-2 147 483 648 ~ 2 147 483 647 (正负20亿)
long8 字节-9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807

其他:

No总结
1若要表示 long 类型需要在数字后加 L 或 l,同样的还有 float 和 double
2二进制前加 0b,八进制前加 0,十六进制前加 0x 或 0X
3Java 中没有 unsigned 类型
41_000_000 即一百万,可以加下划线,使数字更易读,没有实际意义
6.1.2 整数的取值范围与二进制表示

Java 中用补码表示二进制数,补码的最高位是符号位,最高位为 “0” 表示正数,最高位为 “1” 表示负数。

正数补码为其本身;负数补码为其绝对值各位取反加 1. 例如:

+21,其二进制表示形式是 00010101,则其补码同样为 00010101
-21,按照概念其绝对值为 00010101,各位取反为 11101010,再加 1 为 11101011,即 -21 的二进制表示形式为 11101011

计算个整数类型的取值范围的步骤:

  • Step 1:byte 为一字节 8 位,最高位是符号位,即最大值是 01111111,因正数的补码是其本身,即此正数为 01111111,十进制表示形式为 127
  • Step 2:最大正数是 01111111,那么最小负是 10000000 (最大的负数是 11111111,即 -1)
  • Step 3:10000000 是最小负数的补码表示形式,我们把补码计算步骤倒过来就即可。10000000 减 1 得01111111 然后取反 10000000
  • Step 4:因为负数的补码是其绝对值取反,即 10000000 为最小负数的绝对值,而 10000000 的十进制表示是 128,所以最小负数是 -128
  • Step 4:由此可以得出byte的取值范围是 -128 到 +127
  • 另外,整数类型包装对象提供了 MAX_VALUE 和 MIN_VALUE 两个字段,表示指定类型的最大值和最小值,还有从字符串中获取整数的方法 valueOf(String) 等

6.2 浮点数

6.2.1 float 和 double

float

  • float 数据类型是单精度、32位、符合 IEEE 754 标准的浮点数
  • 浮点数不能用来表示精确的值,如货币
  • 例子:float f1 = 234.5f,末尾要加 f

double

  • double 数据类型是双精度、64 位、符合 IEEE 754 标准的浮点数
  • 浮点数的默认类型为 double 类型
  • double 类型同样不能表示精确的值,如货币
  • 例子:double d1 = 123.4
6.2.2 浮点数的存储

浮点数的存储

也就是

一个float类型 = 1bit(符号位)+ 8bits(指数位)+ 23bits(尾数位)
一个double包括 = 1bit(符号位)+ 11bits(指数位)+ 52bits(尾数位)  

于是,float 的指数范围为 -128~+127,而 double 的指数范围为 -1024~+1023,并且指数位是按补码的形式来划分的(和上面的 byte 一样)。因此,float 的范围为 -2^128 ~ +2^127,也即 -3.40E+38 ~ +3.40E+38;double 的范围为 -2^1024 ~ +2^1023,也即 -1.79E+308 ~ +1.79E+308。

6.2.3 精度问题

float 和 double 的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。

float:2^23 = 8388608,一共七位,由于最左为 1 的一位省略了,这意味着最多能表示 8 位数: 2*8388608 = 16777216 。有 8 位有效数字,但绝对能保证的为 7 位,也即 float 的精度为 7~8 位有效数字;double:2^52 = 4503599627370496,一共 16 位,同理,double 的精度为 16~17 位。

在使用浮点类型的时候很容易出现意想不到的结果(了解更多),所以在精度要求比较高的时候建议使用 BigDecimal.

6.3 布尔类型

No总结
1boolean 数据类型表示一位的信息
2这种类型只作为一种标志来记录 true/false 情况
3只有两个取值:true 和 false
4默认值是 false
5Java 中 0 不能代表 false,1 也不能代表 true

6.4 字符类型

No总结
1char 类型是一个单一的 16 位 Unicode 字符(双字节)
2最小值是 \u0000(即为 0)
3最大值是 \uffff(即为 65,535)
4char 数据类型可以储存任何字符

6.5 装箱

  1. Java中存在8种简单类型:boolean, byte, short, int, long, float和double.
  2. 对应的有8种包装类:Boolean, Byte, Character, Short, Integer, Long, Float和Double.
  3. Java 无论装箱和拆箱都存在显示和隐式转换两种方式.
  4. 虽然很多场合下基本数据类型和它的包装类能达到相同的效果,但是使用包装类对基本数据类型进行包装会有额外的开销。所以,能不使用包装类时,尽量使用基本数据类型。

示例:

	public static void main(String[] args) {
		int var1=10;
		Integer obj1=var1;  			// 隐式装箱
		Integer obj2=(Integer)var1;  	// 显示装箱
		int var2=obj1;  				// 隐式拆箱
		int var3=(int)obj2;  			// 显式拆箱
	}

6.6 类型转换

类型转换

  1. 自动类型转换(隐式转换):隐式转换只允许发生在从小的值范围类型到大的值范围类型的转换,转换后数值大小不受影响. 但可能会导致精度降低.
  2. 强制类型转换(显式转换)

关于强制类型转换的总结:

No总结
1强制类型转换有时候会发生截断,比如 300 转换为 byte 类型会得到 44
2不存在到 char 类型的隐式转换
3布尔类型不允许进行任何的类型转换
4整数+浮点数时,浮点数为 double 则另一个是double,浮点数为 float 则另一个是 float,整数是long 则另一个是 long,否则两个都是 int
5上面的转换图实线箭头表示无信息丢失的转换,虚线箭头表示可能有精度损失的转换。可见,从字节小的到字节大的没有损失,从字节大的到字节小的会有精度损失
6将 float 和 double 转换成整数时,对该数字进行截尾,即舍弃小数部分,0.7 将会被转换成 0
7表达式中最大的数据类型决定了表达式的结果,如果将 float 与 double 相乘,结果就是 double 如果将 int 和 long 相乘,结果就是 long

6.7 值类型和引用类型

值类型和引用类型的区别的示例代码:

    public static void main(String ...args) {
        ValueHolder holderPositive = new ValueHolder(1);
        ValueHolder holderNegative = new ValueHolder(-1);
		
        swap(holderNegative, holderPositive); // 交换引用,无法达到交换效果
        System.out.println("holderPositive.value=" + holderPositive.value + ", " + "holderNegative.value=" + holderNegative.value);
        
        swapValue(holderNegative, holderPositive); // 交换引用的字段,可以达到交换效果
        System.out.println("holderPositive.value=" + holderPositive.value + ", " + "holderNegative.value=" + holderNegative.value);
        
        int positive = 1, negative = -1;
        swap(positive, negative); // 交换值类型的值,无法达到交换效果
        System.out.println("positive=" + positive + ", " + "negative=" + negative);
        
        Integer objPos = 1, objNeg = -1;
        swap(objPos, objNeg); // 使用整数类型的包装类型来交换,无法达到交换效果
        System.out.println("objPos=" + objPos + ", " + "objNeg=" + objNeg);

        System.out.println("------------------------");
        positive = negative;
        positive = 2; // 修改一个值类型不会影响另一个
        System.out.println("positive=" + positive + ", " + "negative=" + negative);
		
        holderPositive = holderNegative;
        holderPositive.value = 2; // 修改一个引用会影响到另一个
        System.out.println("holderPositive.value=" + holderPositive.value + ", " + "holderNegative.value=" + holderNegative.value);
    }

    /**
     * 交换两个引用类型的字段:对各个引用的字段进行了修改(相当于修改了内存块上的记录) 
	 */
    private static void swapValue(ValueHolder holder1, ValueHolder holder2) {
        int value = holder1.value;
        holder1.value = holder2.value;
        holder2.value = value;
    }

    /**
     * 交换两个引用类型的引用:仅仅交换了传入的应用的副本(副本指向了其他地方) 
	 */
    private static void swap(ValueHolder holder1, ValueHolder holder2) {
        ValueHolder value = new ValueHolder(holder1.value);
        holder1 = holder2;
        holder2 = value;
    }

    /**
     * 使用整数类型的包装类型来进行交换:这里相当于重新装箱,不会修改原始对象的字段(副本指向了其他地方) 
	 */
    private static void swap(Integer integer1, Integer integer2) {
        int value = integer1.intValue();
        integer1 = integer2.intValue();
        integer2 = value;
    }

    /**
     * 交换两个值类型:交换的只是副本的值,原来的值不会变化
	  */
    private static void swap(int positive, int negative) {
        int value = positive;
        positive = negative;
        negative = value;
    }

    public class ValueHolder {
        public int value;

        public ValueHolder(int value) {
            this.value = value;
        }
    }

输出结果:

	holderPositive.value=1, holderNegative.value=-1
	holderPositive.value=-1, holderNegative.value=1
	positive=1, negative=-1
	objPos=1, objNeg=-1
	------------------------
	positive=2, negative=-1
	holderPositive.value=2, holderNegative.value=2

结论:

No结论
1在 Java 中对基本数据类型,Java 传递值的副本;对一切引用类型,Java 都传递引用的副本
2对于引用类型,两个变量可能引用同一对象,因此对一个变量的操作可能影响另一个变量所引用的对象

Java 基础回顾系列文章,给你的 Java 查缺补漏:

本系列以及其他系列的文章均维护在 Github 上面:Github / Awesome-Java,欢迎 Star & Fork. 如果你喜欢这篇文章,愿意支持作者的工作,请为这篇文章点个赞?!

GD32F103实战:用ADC+DMA实现高精度多通道电压采集与OLED实时显示(附完整工程) 本文详细介绍了如何利用GD32F103的ADC+DMA技术实现高精度多通道电压采集,并通过OLED实时显示数据。文章包含硬件架构设计、ADC配置技巧、DMA传输优化及显示系统实现方案,提供完整工程代码和调试指南,适用于工业传感器和环境监测设备开发。 阅读详情

相关推荐

八路抢答器____一个作品的制作思路

学习了解到一个产品制作完全由一个人去采购,设计,仿真,画PCB。不光是需求的分析还有实现功能时如何搭建电路,和给出一个简单高效的设计方法也是至关重要的。

weixin_73690807的博客 1520

JAVA基础知识点总结

Java 是一门面向对象的编程语言。 语言特点:面向对象,平台无关性,支持多线程,编译与解释并存JVM:Java Virtual Machine,Java 虚拟机。 JRE: Java 运⾏时环境。 JDK: Java Development Kit,它是功能⻬全的 Java SDK。 JDK 包含 JRE,JRE 包含 JVM。Java 程序从源代码到运行主要有三步: 编译:将我们的代码(.java)编译成虚拟机可以识别理解的字节码(.class) 解释:虚拟机执行 Java 字节码,将字节码翻译成机器能

sen_sen97的博客 1万+

Python实现安居客新房数据抓取简易版

本文介绍使用Python爬取安居客新房楼盘数据的方法,重点针对三四线城市。通过分析移动端H5页面结构,采用滚动加载方式获取推荐楼盘列表(class="recomm-list"),从中提取楼盘ID并拼接详情页链接。代码展示了如何解析HTML标签获取楼盘名称、状态、价格、户型等基本信息,并处理图片URL。爬取过程涉及一个一级页面和两个二级页面,同时提到可能遇到的验证码问题将在后续处理。核心代码使用BeautifulSoup解析HTML,requests发送请求,并将数据存入MySQL数据库。

qq_37604998的博客 473

Java基础知识回顾(一)

1. 面向对象和面向过程的区别 面向过程 :面向过程性能比面向对象高。 因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发。但是,面向过程没有面向对象易维护、易复用、易扩展。 面向对象 :面向对象易维护、易复用、易扩展。 因为面向对象有封装、继承、多态性的特性,所以可以设计出低耦合的系统,使系...

鸟不拉诗 258

KIBANA可视化管理界面说明

更说明转自https://blog.csdn.net/IT_ZRS/article/details/125496588 1 主要结构功能 使用浏览器访问 ip:5601 默认端口,进入首页 Discover:日志管理视图 主要进行搜索和查询 Visualize:统计视图 构建可视化的图表 Dashboard:仪表视图 将构建的图表组合形成图表盘 Timelion:时间轴视图 随着时间流逝的数据 APM:性能管理视图 应用程序的性能管理系统 Canvas:大屏展示

tian830937的专栏 7081

Zabbix监控网络设备讲解

Zabbix监控网络设备讲解 本人在研究学习zabbix的时候,网上找过很多如何监控路由,交换,或者是防火墙的文章,但很多都比较散,这里我出一个大概的整合,方便大家参考和学习。本章就拿华三的交换机来做文章。 监控网络设备首先我们需要开启snmp协议,华三怎么开启snmp协议在我的博客里有写到,其次就是找到版本对应的OID,zabbix就是通过抓取设备的OID来做到监控网络设备的,当然zabbix也不仅仅只有通过snmp来监控设备,还有很多别的功能,这些功能我会在以后的博客里面一一更新 文章目录Zab

太阳了文哥的博客 3381

Java基础知识总结(超详细整理)

Java语言的特点,1.面向对象(OOP)就是Java语言的基础,也是Java语言的重要特性。面向对象的概念:生活中的一切事物都可以被称之为对象,生活中随处可见的事物就是一个对象,我们可以将这些事物的状态特征(属性)以及行为特征(方法)提取并出来,并以固定的形式表示。 2.简单好用,Java语言是由C和C++演变而来的,它省略了C语言中所有的难以理解、容易混淆的特性(比如指针),变得更加严谨、简洁、易使用。 3.健壮性、Java的安全检查机制,将许多程序中的错误扼杀在摇蓝之中。 另外,在

龙源IT 的博客 44万+

QT编程之PCM音频播放与采集

Qt5/Qt6通用方案。

深之JohnChen的专栏 1164

Java整型变量和整型常量

目录 1 整型分类 2 Java 语言整型常量的四种表示形式 3 长整型常数的声明 1 整型分类 整型用于表示没有小数部分的数值,它允许是负数。整型的范围与运行Java代码的机器无关,这正是Java程序具有很强移植能力的原因之一。与此相反,C和C++程序需要针对不同的处理器选择最有效的整型。 表2-4整型数据类型 类型 占用存储空间 表数范围 byte 1字节

赵广陆 5657

基于STM32F427的模拟SSI协议绝对式编码器位置反馈通信

基于STM32F427的模拟SSI协议绝对式编码器位置反馈通信

xeke997的博客 6063

C#与硬件开发入门:从零开始搭建你的第一个硬件项目

《C#硬件开发入门指南》摘要:本文介绍了使用C#进行硬件开发的基础知识,重点讲解了通过串口通信控制硬件设备的实现方法。内容包括:C#硬件开发优势、必备基础知识、环境准备步骤,并提供了一个完整的串口数据读取示例代码。文章还给出了进阶学习建议和常见问题解决方案,帮助开发者快速掌握C#与硬件设备通信的基本技能,为进一步开发物联网、工业控制等应用打下基础。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 972

Java基础知识回顾(超详细,万字总结,推荐收藏)

总结目录==本文说明==(一)Java基础1.1.Java历史简述1.2. Java语言的特点1.3. 面向对象与面向过程对比。(1).面向过程(2).面向对象1.4. Java平台的三个版本J2EE、J2SE、J2ME。1.5. JDK、JRE、JVM之间的区别于关系。(1).三者之间的区别:(2).三者之间的关系1.6. 什么是Java环境变量?1.7. javac命令和java命令做什么事情...

李小立 3万+

100:vue+cesium: 加载glb文件,随机位置加载2000架飞机

本示例在 Vue + cesium 项目中随机位置加载2000架飞机,飞机是glb文件,每个大小为571kb。这个示例属于性能优化的范畴内,通常如果用entity加载glb只能显示几个飞机,这里采用primitive的方法来加载。直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果.

大剑师兰特的GIS世界 706

JAVA基础回顾

本文回顾了Java基础语法和面向对象编程的核心知识点。在基础语法部分,介绍了JDK/JRE/JVM关系、变量类型及转换(包括自动和强制类型转换)、进制转换和数组使用。面向对象部分重点讲解了属性与局部变量的区别、方法重载与重写的规则、this和super关键字的使用场景,以及值传递机制。特别强调数据类型转换的注意事项、方法重写的具体规范,以及通过代码示例演示了构造器调用链和父子类属性/方法访问的方式。这些内容为Java开发者提供了全面的基础回顾和重要概念梳理。

qq_47155275的博客 1326

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Java基础总结回顾

title: Java基础总结回顾 date: 2022-04-12 17:31:14 tags: Java categories: Java cover: https://cover.png feature: false 1. 说明 1.1 编译与运行 编译:是指将编写的 Java 源文件翻译成 JVM 认识的 class 文件,在这个过程中, javac 编译器会检查所写的程序是否有错误,有错误就会提示出来,如果没有错误就会编译成功 运行:是指将 class文件 交给 JVM 去运行,此时 J.

凡的博客 3098

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Java基础知识点回顾

毕设需要,迅速回顾一遍Java程序设计的基础知识。 Java语言规范、API、JDK、IDE的含义: Java语言规范是Java语法和语义技术性定义,API是应用程序接口(Java预定义类和接口),Java开发工具包(JDK)包含软件库、编译器、解释器以及其他工具,集成开发环境(IDE)提供编辑、编译、调试和在线帮助功能。 Java平台版本: Java SE:允许开发和部署在桌面、服务器和嵌入...

Ray的博客 1万+

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

JAVA基础知识回顾

JAVA基础知识回顾 晚间窗外吹来的风令人清醒,喝一口杯中的温水,适合回顾下JAVA基础知识,温故而知新。 JAVA的版本 JAVA1.5(JDK5.0)是一重大版本,新增了自动装箱拆箱、枚举、静态导入、可变参数、内醒等功能。 JAVA1.8(JDK8.0)目前较为常用,目前国内大部分公司使用的都是JDK8.0。 JAVA平台版本 J2SE:标准版,为开发普通桌面和商务应用程序提供的解决方案是其他两者的基础,可完成一些桌面程序的开发。 J2ME:小型版,为开发电子消费产品和嵌入式设备提供的解决方案。 J2E

qq_43558335的博客 879

Java 知识点基础回顾

本文回顾了Java基础知识点,主要包括Java版本分类(JavaEE、JavaSE、JavaME)、JDK/JRE/JVM的关系及安装配置、变量命名规则与数据类型(基本类型和引用类型)、数据类型转换规则(自动转换和强制转换)、以及运算符使用(算术、赋值、关系、逻辑等)。文章强调了Java跨平台特性、字符集编码原理、变量作用域和命名规范,并通过代码示例说明了类型转换中的常见问题和运算时的自动类型提升现象。全文系统梳理了Java基础概念,为后续深入学习打下基础。

Eric_smxu的博客 904

java基础回顾-day02

第二天学习,接着挖坑,以及idea的学习。

d5_fengzi的博客 1616

java基础回顾1

java基础回顾 第一阶段—> 计算机基础 1. JDK JRE JVM JVM:(Java Virtual Machine)Java虚拟机,我们在进行java开发的时候,首先需要编写java源代码, 源代码经过编译器编译,编译成二进制文件(字节码文件.class文件),经过解释器对字节码文件进行解释翻译才能执行。 而JVM中包含了解释器(不同操作系统解释器不一样),所以java跨平台就是通过JVM来实现的。 确切的来说,java跨平台是因为JVM中的解释器跨平台 JDK:(Java Develop

weixin_69015220的博客 190

java 基本知识回顾1

基本类型介绍: java提供了八种基本类型,六种数字类型(四个整数型,两个浮点型),一种字符类型,一种布尔类型。 八大类型:byte,short,int,long,float,double,boolean,char float,double小数位精度是多少?为什么? float是7位,double是16位。原因是float的尾数位是23位,float的尾数位是52位,用2的负...

The_flying_pig的博客 387

【Java基础回顾】Java基础回顾重难点笔记

Java基础回顾一、Java概览1.Java的运行过程2.Java的跨平台的解释2.Maven基础二、Java的基本语法1.Java中的注释2.Java中的关键字3.关键字总结3.java中的标识符4.多态5.泛型6.反射7.集合8.正则9.引用分类10.Java八种数据类型三、集合1.List2.Set3.Map四、 一、Java概览 1.Java的运行过程 🍎Java程序运行时,必须经过编译和运行两个步骤。 🍊首先将后缀名为.java的源文件进行编译,最终生成后缀名为.class的字节码文件。然后Ja

斯基的朦胧 900

Java基础回顾

基础回顾篇序言什么是JavaJDK下载与环境配置环境配置 序言 在很早之前就想出一篇基础方面的总结,但是思路一直不清晰,还是想在巩固一下这方面毕竟基础还是很重要的。接下来我将从什么是java到JDBC的操作列出,话不多说直接low它 什么是Java Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂

藤井大叔的博客 475

java学习回顾与总结

网易云java架构师课程学习,回顾总结 一.基础回顾 1.java基础内容 1.1 java语法 1.2 方法的重写与重载,覆盖与隐藏 1.3 java修饰词与访问权限 1.4 继承 1.5 封装 1.6 多态 1.7 super与this 1.8 内存分配 1.9 封装 1.10 继承 1.11 封装 2.java中级内容 二.重点掌握 三.个人总结 四.未来展望 ...

lk的博客 730

1.0、Java中基础学习的回顾

Java中的JDK、JRE、JVM JDK:Java Development Kit(Java开发工具包) JRE:Java Runtime Environment(Java运行环境) JVM:Java Virtual Machine(Java虚拟机) JDK中包含有JRE,JRE中包含有JVM,所以呢我们不需要单独去安装JRE,只需要安装部署好JDK的版本以及运行环境即可八种数据的基本类型: byte --> short --> cha

m0_52433668的博客 508
上一篇: Android 内存缓存框架 LruCache 的源码分析
下一篇: Java 基础回顾-2:面向对象
开发者如是说
博客等级 码龄10年 67粉丝 163原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值