一、思维导图
二、流程图
三、DFD数据流图
四、时序图
五、UML类图
一、思维导图
二、流程图
三、DFD数据流图
四、时序图
五、UML类图
右移>>是指带符号右移,如果最高位的符号位为1,则右移时左侧补上的空位用1填充,否则用0填充
而无符号右移>>>,不管左侧最高位是1还是0,左侧补上的空位统统用0填充,如下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public static void main(String[] args){ int i = 390228; String ibstr = int2BitStr(i); System.out.println(ibstr); int i1 = i << 13 >>> 29; int i2 = i << 13 >> 29; System.out.println("无符号右移:" + int2BitStr(i1)); System.out.println("带符号右移:" + int2BitStr(i2)); System.out.println("无符号右移:" + i1); System.out.println("带符号右移:" + i2); } String int2BitStr(int value){ String ibstr = Integer.toBinaryString(value); // 显示全部二进制字符,32位 while (ibstr.length() < 32){ ibstr = "0" + ibstr; } String ibstr1 = ibstr.substring(0, 8) + " " + ibstr.substring(8, 16) + " " + ibstr.substring(16, 24) + " " + ibstr.substring(24, 32); return ibstr1; } |
看输出结果:
1 2 3 4 5 |
00000000 00000101 11110100 01010100 无符号右移:00000000 00000000 00000000 00000101 带符号右移:11111111 11111111 11111111 11111101 无符号右移:5 带符号右移:-3 |
我们从第13位开始左移,即第二字节的101那里,左移后的结果如下,右侧应该有一些0用省略号代替了
101 11110100 01010100…..
我们再右移29位,即只剩下101,那么如果用>>前面将被补上很多的1,如果使用>>>,则会补很多0
在app/build.gradle中的android节点中增加如下代码:
1 2 3 4 5 6 7 8 9 10 |
android { //....忽略其他代码 android.applicationVariants.all { variant -> variant.outputs.all{ output->outputFileName = new File(variant.name, "myapp_" + buildType.name + "_${variant.versionName}(${variant.versionCode}).apk"); } } } |
myapp_固定的名称
buildType.name 为release或者debug
${variant.versionName}为versionName
${variant.versionCode}为versionCode
生成的apk的文件名为myapp_debug.apk
举例:short类型的值范围为-32768 ~ 32767,看下面这些对short值的操作
1 2 3 4 5 6 7 8 9 10 11 |
short s32768 = (short) 32768; System.out.println("32768强制转换后的结果为:" + s32768); short s32769 = (short) 32769; System.out.println("32769强制转换后的结果为:" +s32769); short s65535 = (short) 65535; System.out.println("65535强制转换后的结果为:" +s65535); short s65536 = (short) 65536; System.out.println("65536强制转换后的结果为:" +s65536); |
最后的输出结果为:
1 2 3 4 |
32768强制转换后的结果为:-32768 32769强制转换后的结果为:-32767 65535强制转换后的结果为:-1 65536强制转换后的结果为:0 |
对于长度小于或者等于int的数据类型,如short, byte在进行如下运算后,其他运算结果为int型
<<,>>,>>>,&,|,^,+,-,*,/
如下代码,就会提示你将运算强制转换成short类型
1 2 |
short b222 = 10; short sdddd = b222 - 8; |
可以通过&运算将有符号号转为无符号数,
对于byte类型& 0xFF,
对于short类型& 0xFFFF,
对于int类型& 0xFFFFFFFF
注意&运算完的结果是一个int型的值
下面看一个示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public static void main(String[] args){ byte negb = -8; int negbint = negb & 0xFF; int castint = (int)negb; System.out.println("-8: " + byte2binary(negb)); System.out.println("-8 & 0xFF: " + negbint); System.out.println("negbint: " + int2binary(negbint)); System.out.println("-8 强制转换成int: " + castint); System.out.println("castint: " + int2binary(castint)); } public static String int2binary(int value){ String ibstr = Integer.toBinaryString(value); // 显示全部二进制字符,32位 while (ibstr.length() < 32){ ibstr = "0" + ibstr; } String ibstr1 = ibstr.substring(0, 8) + " " + ibstr.substring(8, 16) + " " + ibstr.substring(16, 24) + " " + ibstr.substring(24, 32); return ibstr1; } |
运行结果:
1 2 3 4 5 |
-8: 11111000 -8 & 0xFF: 248 negbint: 00000000 00000000 00000000 11111000 -8 强制转换成int: -8 castint: 11111111 11111111 11111111 11111000 |
强制类型转换并没有改变符号。
负数的左移位操作会使数据保持为负数
Windows和Ubuntu18双系统,最近从Windows系统切回ubuntu后windows的E盘可读不可写
从网上查可通过ntfsfix命令来解决,如下:
1 2 3 4 5 6 7 |
liuderu@liuderu-Inspiron-5577:~$ sudo ntfsfix /dev/sdb3 Mounting volume... OK Processing of $MFT and $MFTMirr completed successfully. Checking the alternate boot sector... OK NTFS volume version is 3.1. NTFS partition /dev/sdb3 was processed successfully. liuderu@liuderu-Inspiron-5577:~$ |
如果上述命令失败,可以先尝试umount一下,如下:
umount /dev/sdb3
个人比较喜欢c语言,所以后面的编程都会使用c语言。
使用c语言的话可以使用用wiringPi类库。
1、查看是否安装wiringPi类库,输入下面的命令,如果返回版本信息则表示已安装wiringPi库
1 |
$ gpio -v |
2、如果没有安装,输入下面的命令安装
1 |
sudo apt-get install wiringpi |
3、wiringPi源码
github上有一个wiringPi的代码库,但那个并不是wiringPi的源码,其源码在下面这个地址中
将Led灯的两个针脚分别连到GND和GPIO0两个接口上,网上有的教程还说要连上一个电阻,但是俺没有,就直接连上了。
新建一个ledblink.c文件,然后输入下面的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <stdio.h> #include <wiringPi.h> #define LED 0 #define BLINK_INTERVAL 500 int main(void){ printf("LED blink!\n"); wiringPiSetup(); pinMode(LED, OUTPUT); for(;;){ digitalWrite(LED, 1); delay(BLINK_INTERVAL); digitalWrite(LED, 0); delay(BLINK_INTERVAL); } return 0; } |
输入下面的命令编译
1 |
gcc -o ledblink ledblink.c -lwiringPi |
编译完成后,会生成一个ledblink的可执行程序,输入./ledblink运行,看led灯是不是开始闪烁了!
事件Event:主要用做数据的载体,里面只是包含要传递的数据。
监听器Listener:事件真正被触发的地方,其handle方法接受传入的Event对象,并在此处理Event中带来的数据。
打开App\Providers\EventServiceProvider.php,给$listen数组赋值要添加的事件和监听器,可定义多个事件,每个事件也可以定义多个监听器。
比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
<?php namespace App\Providers; use Illuminate\Contracts\Events\Dispatcher as DispatcherContract; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider { /** * The event listener mappings for the application. * * @var array */ protected $listen = [ 'App\Events\UserReigisterEvent' => [ 'App\Listeners\UserRegisterListener', ], 'App\Events\UserLoginEvent' => [ 'App\Listeners\UserLoginListener', ], ]; /** * Register any other events for your application. * * @param \Illuminate\Contracts\Events\Dispatcher $events * @return void */ public function boot(DispatcherContract $events) { parent::boot($events); // } } |
在控制台输入命令:
php artisan event:generate
执行完以后可以看到App\Event和App\Listeners两个目录下多了相应的php类
Event类主要用于运输数据,在_construct函数的参数中传入,并将值保存在内部成员变量中,示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<?php namespace App\Events; use App\Events\Event; use Illuminate\Queue\SerializesModels; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use App\User; class UserLoginEvent extends Event { use SerializesModels; public $user; public $logintimes; /** * Create a new event instance. * * @return void */ public function __construct(User $_user, $_logintimes) { $this->user = $_user; $this->logintimes = $_logintimes; } /** * Get the channels the event should be broadcast on. * * @return array */ public function broadcastOn() { return []; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<?php namespace App\Listeners; use App\Events\UserLoginEvent; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; class UserLoginListener { /** * Create the event listener. * * @return void */ public function __construct() { // } /** * Handle the event. * * @param UserLoginEvent $event * @return void */ public function handle(UserLoginEvent $event) { echo $event->logintimes; echo $event->user->username; } } |
比如在用户登录成功的地方调用前面定义的事件
1 2 |
$loginevent = new UserLoginEvent($loginuser, $logintimes); event($loginevent); |
本文基于Ubuntu16,pi zero WH,树莓派镜像版本2019-06-20_raspbian_full
树梅派官方推荐使用Etcher制作镜像,但是下载速度实在是太慢了,使用dd也可以搞定。
官网镜像下载地址:https://www.raspberrypi.org/downloads/raspbian/
首先下载树梅派系统镜像包,是一个zip文件,如:2019-06-20_raspbian_full_latest.zip
解决zip包后得到img镜像文件,如:2019-06-20-raspbian-buster-full.img
将sd卡连接电脑,然后执行df -h
拔掉sd卡后再执行一次df -h
有变化的那一项即是sd卡的设备名称,如:/dev/sdc1
/dev/sdc即是sd卡的主设备名,先执行下面命令卸载它的子分区
1 |
umount /dev/sdc1 |
假如还有sdc2、sdc3统统卸载掉
执行下面的命令烧录系统
1 |
dd bs=4M if=./2019-06-20-raspbian-buster-full.img of=/dev/sdc |
if=后面是镜像所在的路径
of=后面是sd卡设备名称
一直有一个担心,对于不同的数据类是否可以用同一个gson实例,今天研究了一下,不仅是可以,而且最好是这样使用。看代码Gson.java中的getAdapter方法,一开始就是在typeTokenCache这个缓存中找type相关的TypeAdapter。
1 2 3 4 5 6 7 8 |
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) { TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type); if (cached != null) { return (TypeAdapter<T>) cached; } //...省略其他代码 } |
因此复用一个gson的实例会省去匹配TypeAdapter(当然还有new Gson())的时间。
如下代码实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import java.util.Random; public class GsonTest { class User{ int id; } class Score { int score; } public static void main(String[] args){ String jsonstr= "{\"id\": "; String jsonstr1= "{\"score\": "; long start = System.currentTimeMillis(); StringBuilder stringBuilder = new StringBuilder(""); Random random = new Random(1000); Gson gson = new Gson(); //复用一个实例 for(int i = 0; i < 1000 ; i++){ stringBuilder.setLength(0); stringBuilder.append(jsonstr).append(random.nextInt(10000)).append("}"); System.out.println(stringBuilder.toString()); //Gson gson = new Gson(); //每次创建实例 User u = gson.fromJson(stringBuilder.toString(), User.class); System.out.println("userid: " + u.id); stringBuilder.setLength(0); stringBuilder.append(jsonstr1).append(random.nextInt(10000)).append("}"); System.out.println(stringBuilder.toString()); Score score = gson.fromJson(stringBuilder.toString(), Score.class); System.out.println("score: " + score.score); } System.out.println("Time: " + (System.currentTimeMillis() - start)); } } |
在我机器上测试不复用的话用时220-260毫秒之间(非常不稳定),复用120毫秒。
TypeToken其实是为了给标识一个泛型类中的T,对于普通的类我们通过getClass().getName就可以得到类的标识,但是对于泛型类,只能得到泛型外层的类名,并不能得到泛型外层类+泛型类这样的全名。
如下代码:
1 2 |
List<Integer> intlist = new ArrayList<Integer>(); System.out.println(intlist.getClass().getName()); |
输出结果是:java.util.ArrayList,而不是java.util.ArrayList<java.lang.Integer>
使用TypeToken来获取就是另外一种情况了,看下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import java.lang.reflect.Type; public class GenericTypeTest { static class GType<T> { T t; public GType(T t) { this.t = t; } String getGtName(){ return t.getClass().getName(); } } public static void main(String[] args){ Integer i = new Integer(10); GType<Integer> gTypeInt = new GType<Integer>(i); System.out.println("Type from getClass().getName(): " + gTypeInt.getGtName()); GType<GType<Integer>> gtt = new GType<GType<Integer>>(gTypeInt); System.out.println("Type from getClass().getName(): " + gtt.getGtName()); Type type = new TypeToken<GType<Integer>>(){}.getType(); System.out.println("Type from typetoken: " + type.toString()); } } |
输出结果:
1 2 3 |
Type from getClass().getName(): java.lang.Integer Type from getClass().getName(): cn.bcoder.libgsontest.GenericTypeTest$GType Type from typetoken: cn.bcoder.libgsontest.GenericTypeTest$GType<java.lang.Integer> |
1. ConstructorConstructor – 返回一个函数可以给要操作的类新建一个实例对象。
2. InstanceCreator – 用于给没有无参数构造函数的类,创建一个实例的一个接口。解释:gson在反序列时需要创建类的一个实例,如果该类没有无参数构造函数(如:三方库中的类),则会出现异常,所以开发者需要新建一个类实现这个接口,并用该类可用的构造函数新建一个实例。并使用下面方式Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdInstanceCreator()).create();注册到gson中。
3. FutureTypeAdapter – 用于缓存TypeAdapter。为什么不用TypeAdapter的实例缓存?因为TypeAdapter是个虚类 :-D
转载自:http://shumeipai.nxez.com/2017/09/13/raspberry-pi-network-configuration-before-boot.html
不算是什么新功能了,在树莓派3B发布后不久,树莓派官方 Raspbian 系统久加入了允许在开机前对 WiFi 网络进行配置的机制。
注意,这个方法仅适用于全新安装树莓派系统到 SD 卡之后没有做过任何 Wi-Fi 配置的情况下有效。如果你之前配置过 Wi-Fi,再用本方法系统会默认使用已有的配置而忽略这里的配置。因此建议使用前重新安装系统。
用户可以在未启动树莓派的状态下单独修改 /boot/wpa_supplicant.conf
文件配置 WiFi 的 SSID 和密码,这样树莓派启动后会自行读取 wpa_supplicant.conf 配置文件连接 WiFi 设备。
操作方法简单:将刷好 Raspbian 系统的 SD 卡用电脑读取。在 boot 分区,也就是树莓派的 /boot
目录下新建 wpa_supplicant.conf 文件,按照下面的参考格式填入内容并保存 wpa_supplicant.conf 文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
country=CN ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 network={ ssid="WiFi-A" psk="12345678" key_mgmt=WPA-PSK priority=1 } network={ ssid="WiFi-B" psk="12345678" key_mgmt=WPA-PSK priority=2 scan_ssid=1 } |
说明以及不同安全性的 WiFi 配置示例:
#ssid:网络的ssid
#psk:密码
#priority:连接优先级,数字越大优先级越高(不可以是负数)
#scan_ssid:连接隐藏WiFi时需要指定该值为1
如果你的 WiFi 没有密码
1
2
3
4
|
network={ ssid="你的无线网络名称(ssid)" key_mgmt=NONE } |
如果你的 WiFi 使用WEP加密
1
2
3
4
5
|
network={ ssid="你的无线网络名称(ssid)" key_mgmt=NONE wep_key0="你的wifi密码" } |
如果你的 WiFi 使用WPA/WPA2加密
1
2
3
4
5
|
network={ ssid="你的无线网络名称(ssid)" key_mgmt=WPA-PSK psk="你的wifi密码" } |
如果你不清楚 WiFi 的加密模式,可以在安卓手机上用 root explorer 打开 /data/misc/wifi/wpa/wpa_supplicant.conf
,查看 WiFi 的信息。
如果通过 ssh 连接树莓派出现 Access denied 这个提示则说明 ssh 服务没有开启。要手动开启的话,和 WiFi 配置相似,同样在 boot 分区新建一个文件,空白的即可,文件命名为 ssh。注意要小写且不要有任何扩展名。
树莓派在启动之后会在检测到这个文件之后自动启用 ssh 服务。随后即可通过登录路由器找到树莓派的 IP 地址,通过 ssh 连接到树莓派了。(有关开启 SSH 服务的详细方法)
如果需要远程桌面方式操作树莓派,可以通过 ssh 安装 xrdp,再用 Windows 的远程桌面客户端连接到树莓派。
这个小技巧对于没有有线网卡、没有标准 USB 接口来直连键鼠,但集成了 WiFi 的树莓派 Zero W 尤其实用。