概要:今天想运用一下已学的知识试着实现一下微信的聊天界面。主要实现的功能只是聊天内容的发送和显示。
这其实是《第一行代码》中的一个实战样例,主要想记录一下心得体会。
关于Android Studio标红的解决方法
Java可变参数
JAVA类定义之初始代码块
今天学长出了一道题,我发现我竟然对初始化代码块的存在一无所知。
初始化代码块(initialization block)是初始化数据域的第三种机制(前两种分别是构造器和声明时赋值)。只要构造类的对象,只写代码块就会被自动执行,不需要调用。1
2
3
4
5
6
7
8
9
10
11class A
{
//数据域
private int id;
private int name;
//object initilization block
{
id = 4;
name++;
}
}
构造类时,先运行初始化代码块,再运行构造方法的主体。
注:
为了避免循环定义,不要读取初始化以后的域
Java是按照编程顺序来执行实例变量初始化器和实例初始化器中的代码的,并且不允许顺序靠前的实例代码块初始化在其后面定义的实例变量
对静态域进行初始化,可直接提供一个初始化值(private ststic int id = 1;),也可通过静态的初始化块进行初始化。1
2
3static{
}
再类第一次加载时,即进行静态域的初始化。且所有的静态初始化语句与静态初始化块都将按类的定义顺序执行。
注:
JVM加载类时执行(仅执行一次)
- 随类的加载执行,只执行一次,并优先于主函数main。
- 静态代码初始化块是给类初始化,构造代码块是给对象初始化。
- 静态代码块中的变量是局部变量,等同于普通函数中的局部变量。
- 一个类中可以有多个静态代码块。
当涉及到继承时,按照如下顺序执行:
执行父类的静态代码块,初始化父类静态成员变量
执行子类的静态代码块,初始化子类静态成员变量
执行父类的构造代码块,执行父类的构造函数,初始化父类普通成员变量
执行子类的构造代码块,执行子类的构造函数,初始化子类普通成员变量
I.1
2
3
4
5int a;
{
b = a;
}
int b;
II.1
2
3
4
5int b;
{
b = a;
}
int a;
I能够通过编译,但II报错:非法前引用。
静态代码块只能对其之前的数据进行访问,对于其之后的数据可以赋值但不能被访问。
—《深入理解Java虚拟机》
总结:
调用构造器的具体处理步骤:
- 所有数据域被初始化为默认值(0,false,null)
- 按类声明的顺序执行 与初始化语句和初始化
- 若构造器首行调用了第二个构造器,则执行第二个构造器主体
- 执行构造器
一个Java对象的创建过程往往包括类初始化和类实例化两个阶段,类实例化包括实例变量初始化、实例代码块初始化以及构造函数初始化
实际上,如果我们对实例变量直接赋值或者使用实例代码块赋值,那么编译器会将其中的代码放到类的构造函数中去,并且这些代码会被放在对超类构造函数的调用语句之后,构造函数本身的代码之前
实例化对象时,JVM首先会检查相关类型是否已经加载并初始化,如果没有,则JVM立即进行加载并调用类构造器完成类的初始化。在类初始化过程中或初始化完毕后,根据具体情况才会去对类进行实例化。
其实一般也很少使用到初始化块,因为都是在构造方法内完成类的初始化。初始化块一般适用于加载类时加载本地库。
搭建Hexo博客与github部署指南
Git
因为经常会要用到Git以及Github,首先安装Git:https://git-scm.com/download/linux1
$ apt update; apt install git
Node.js
Hexo是一款基于Node.js的静态博客框架,所以我们还需要安装它:https://nodejs.org/en/download/
下载后移动到任意路径下解压,tar.xz解压命令为tar -xvJf 。然后建立全局软链接(全局变量)
sudo ln -s /../node.js/bin/npm /usr/local/bin/
sudo ln -s /../node.js/bin/node /usr/local/bin
然后检测是否成功1
2node -v
npm -v
如果成功会出现版本号,这里是v8.11.1与5.6.0
附: node.js源码安装教程
Hexo
然后开始安装Hexo。1
npm install hexo-cli -g //这是用npm方式部署hexo静态博客。
遇到安装异常sh: 1: node-gyp: Permission denied,运行1
2npm config set unsafe-perm true //以后,再运行
npm install -g hexo-cli //但是我好像没有遇到这个问题。
我的话主要是教程里都没有提醒我创建hexo的全局变量,导致我一直显示未找到命令。创建了变量后就成功了。这里用1
hexo -v
若出现版本信息,则安装成功,已在本地机器上搭建起了Hexo环境。
部署Hexo文件夹。
任意位置创建文件夹hexo,在该文件夹内初始化hexo1
2hexo init //将该文件夹初始化为博客目录
npm install
安装相关依赖包,具体安装内容可以在package.json文件里找到
其中,_config.yml是配置站点的文件,public是hexo生成的静态站点文件夹,scaffolds是模板文件夹,source是存在用户资源的文件夹,themes是主题文件夹。接着1
hexo generate
生成hexo静态页面,将我们写的Markdown文件 (.md后缀) 转换成html静态页面
生成完毕之后,hexo文件夹内又多了一个public文件夹,这就是静态博客的目录,如果我们需要部署到服务器或者托管平台,只要将hexo生成静态之后,将public文件夹里的文件传上去就可以了。其他系统文件还是放在本地。
博客预览
1 | hexo server |
然后在浏览器中输入地址http://localhost:4000
使用1
hexo server -p 5000
可以改变接入端口。默认接入端口为4000。但是听说如果打开了福昕阅读器,他会占用4000端口。
也可以在_config.yml内加上如下代码更改hexo-server运行时的端口号:1
2
3
4server:
port: 5000
compress: true
header: true
也可以先使用1
netstat -ant |grep 4000
命令查看端口被什么占用,若是个没人用的东西,就kill掉这个进程
进一步配置
找到博客根目录下的配置文件_config.yml,# Site部分,title是博客的名字,subtitle是副标题,author即为作者名字。
接下来是下一部分:
#将Hexo托管到Github
首先现在Github账户上新建一个仓库,作为以后博客的存放位置。仓库名为GithubUserName.github.io,然后Create
配置Github:
配置Name和Email:1
2$ git config --global user.name "yourName"
$ git config --global user.eamil "email@example.com"
在某个项目根路径下面可以设置单独的Email与姓名:1
2git config user.name "tiemaocsdn"
git config user.email "tiemaocsdn@qq.com"
创建公钥1
ssh-keygen -C "email@example.com" -t rsa
在用户~/.ssh/下建立相应的密钥文件~/.ssh/id-rsa.pub,gedit打开该文件,复制文本。
添加公钥:
在Github首页点击setting,选择New SSH KEY,然后将密钥文件复制进去。
Hexo部署到github
打开hexo文件下的_config_yml,在底部添加1
2
3
4deploy:
type: git
repo: https://github.com/GithubUserName/GithubUserName.github.io
branch: master
注:这是关键点!首先:后边必须有一个空格!然后次行repo有的教程是repository,听说会有bug;然后几乎所有教程io后会加.git,其实不用不知道为什么。最靠谱的是直接将你的仓库地址复制过来。
最后,因为hexo3.0以后deploy与hexo分离,所以还添加个插件就能将博客push到git上
npm install hexo-deployer-get –save
然后不要忘了上传1
2
3
4
5
6
7
8hexo g -d
hexo g 为生成静态文件
hexo g -d 为文件生成后立即部署网站
或者hexo g 然后hexo d也行
hexo d -g 为部署网站前生成静态文件
git push [-u origin master] 仓库数据进行同步
git pull 每次修改前进行更新
编写博客1
2
3hexo new "博客名"
显示博客的.md文件地址,打开即可编写
hexo g -d
本地Git库与远程仓库(Github)的关联建立
只有在本地初始化git后才能使用git。
选择一个文件夹,执行命令1
git init 初始化该本地文件夹为git管理的本地仓库
注:Git将自动创建唯一一个master分支。当前目录下多了一个.git的目录(隐藏文件夹),这个目录是Git来跟踪管理本地库的,修改文件需谨慎,易破坏Git仓库。可通过删除目录来断开本地仓库与远程仓库的连接,就像刚刚没有创建本地仓库,每次更新都需要输入用户名与密码。
关联指定远程仓库1
git remote add origin git@github.com:YotrolZ/helloTest.git
注:origin即为远程库的名字,这是Git默认的叫法,可以改成别的;
git@github.com:YotrolZ/helloTest.git 为我们远程仓库的路径,可为url或仓库名。这里还直接仓库地址保险。
此时,可以尝试git pull拉取。
链表入门
静态列表与动态列表
- 指向结构体的指针不指向结构体成员,因为类型不同
- 定义动态链表,需要约定好链表结束的条件。
- 动态链表: 让p1指向新开辟的结点,p2指向链表最后一个结点,把p1所指的结点连接在p2所指的结点后面。
- 用malloc开辟结点1(n=1),使p1指向它。
1
p1 = (struct Name *) malloc (Name长度);
- 输入节点数据;
- 链入结点2(n=2),p1的值赋给p2 -> next,此时p2指向第一个节点,故 p2 -> next = p1 将结点2的地址赋给结点1的 next;
- 使 p2 = p1,即使p2指向新结点。在建立链表的循环中,例1是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22struct Student* creat()
{
struct Student *p1, *p2, *head;
n = 0;
p1 = p2 = (struct Student *)malloc(Len);
scanf("%d%d",&(*p1).num, &(*p1).age);
head = NULL;
while((*p1).num != 0)
{
n++;
if(n == 1)
head = p1;
else
(*p2).next = p1; //这里跟我的顺序不太一样,可以思考一下
p2 = p1;
p1 = (struct Student *)malloc(Len);
// p2 = p1;
scanf("%d%d",&(*p1).num, &(*p1).age);
}
(*p2).next = NULL;
return head;
}
- 连接
- 创建
- 赋值(此时p2在旧结点p1在新结点)
1 | struct Student* creat() |
在建立链表的循环中,例2是
- 创建
- 链接
- 赋值(此时p2与p1都在新结点)
Python的itchat接口
关于itchat的学习体验
pip模块下载
在控制台窗口用pip install下载,并用1
pip list
查看,已载入。在python-Shell下始终无法导入。后来改用命令pip3 install安装成功。pip3 list已载入,再导入,成功!
itchat初体验
- 获取网页登陆的二维码
1
itchat.auto_login( )
- 发信息
1
itchat.send
列表中只有一个元素,是一个字典,引索”UserName”得到微信号,是一长串十六进制的数字1
itchat.search_friends(name = u"备注名称或昵称") #获取对方的全部信息(列表)
下图是失败与成功的返回信息。1
itchat.send(msg = ' ',toUserName = user)
2018/1/19/13:26
今天开始系统了解itchat。这应该是官方的文档:
itchat官方文档
-入门实例
itchat.auto_login( ) 登陆账号
itchat.logout( ) 注销账号
itchat.run( ) 运行
user = itchat.search_friends(name = “昵称或备注”) 获取对方账户信息
itchat.send(msg = “文本信息”, toUserName = “对方微信号”)
user[0].send(msg = “文本信息”)
PS:
微信移动端只要退出登录(断网),其网页版PC版e也会被强制登出,故需要保持移动端登录状态
有一些微信账户天生不能给自己发信息,可以改用filehelper
用对方发给自己的文本消息回复1
2
3
4
5
6import itchat
@itchat.msg_register(itchat.content.TEXT)
def text_reply(msg):
return msg.text
itchat.auto_login()
itchat.run()
itchat.search_friend 方法搜索用户
- 仅获取自己的用户信息:
1
itchat.search_friends()
- 获取特定UserName的用户信息:
1
itchat.search_friends(userName='')
- 获取备注、微信号、昵称中的任何一项等于name键值的用户:
1
itchat.search_friends(name='')
- 获取备注、微信号、昵称分别等于相应键值的用户:
1
itchat.search_friends(wechatAccount='')
- 前两项功能可以一同使用:
1
itchat.search_friends(name=' ', wechatAccount=' ')
(正式开始预警+分割线。。。)
-登陆配置
itchat提供了登陆状态暂存,关闭程序后一定时间内不需要扫码即可登录。由于目前微信网页版提供上一次登录的微信号不扫码直接手机确认登陆,所以如果开启登陆状态暂存将会自动使用这一功能。该方法会生成一个静态文件itchat.pkl,用于存储登陆的状态。1
itchat.auto_login(hotReload = True)
-Send方法回复
返回Bool值。对象为空则发给自己。1
send(msg='Text Message', toUserName=None)
请确保该程序目录下存在:gz.gif 以及 xlsx.xlsx1
2
3itchat.send('@img@%s' % 'gz.gif') #识别为发送图片
itchat.send('@fil@%s' % 'xlsx.xlsx') #识别为发送文件
itchat.send('@vid@%s' % 'demo.mp4') #识别为发送视频
其他:1
2
3
4send_msg(msg='Text Message', toUserName=None)
send_file(fileDir, toUserName=None)
send_img(fileDir, toUserName=None)
send_video(fileDir, toUserName=None) #需保证发送视频为一实质的mp4文件
注册消息方法
itchat将根据接收到的消息类型寻找对应的已经注册的方法。如果一个消息类型没有对应的注册方法,该消息将会被舍弃。在运行过程当中也可以动态注册方法,注册方式与结果不变。
不带具体对象注册,将注册为普通消息的回复方法
1 | def simple_reply(msg): |
带对象参数注册,对应消息对象将调用该方法
1 | @itchat.msg_register(TEXT, isFriendChat=True, isGroupChat=True, isMpChat=True) |
注册消息的优先级
优先级分别为:后注册消息先于先注册消息,带参数消息先于不带参数消息。1
2
3from itchat.content import *
@itchat.msg_register
@itchat.msg_register(TEXT)
看了这个例子,我也终于懂了itchat处理信息的机制。@msg_register方法注册信息类型,其后定义函数来表明处理该类信息的方法。
尝试打印1
2
3
4search_friends( )
list = itchat.search_friends()
for i in list:
print(i)
得到一个字典,保存自己的用户信息
MemberList UserName City DisplayName PYQuanPin RemarkPYInitial Province KeyWord RemarkName PYInitial EncryChatRoomId Alias Signature NickName RemarkPYQuanPin HeadImgUrl UniFriend Sex AppAccountFlag VerifyFlag EncryChatRoomId HideInputBarFlag AttrStatus SnsFlag MemberCount OwnerUin ContactFlag Uin StarFriend Statues WebWxPluginSwitch HeadImgFlag
写了一段代码实现一个简单的微信自动回复。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23import itchat
from itchat.content import *
count = 0
@itchat.msg_register(PICTURE, RECORDING)
def all_reply(msg):
global count
print("收到一条信息。。(第%d条)" % count)
return "我还看不懂图片语音,发文字谢谢。。"
@itchat.msg_register(TEXT)
def text_reply(msg):
global count
count += 1
print("收到一条信息。。(第%d条)" % count)
if count == 1:
return '嗯?'
elif count == 2:
return "说什么大点声。。"
elif count == 3:
return "好吧我是机器人。。"
elif count >= 4:
return "我看到了马上回复你哈。。"
itchat.auto_login(hotReload = True)
itchat.run()
但是前边那个注册信息不带参数却能处理所有信息的语句我还是无法实现。
关于动态注册,并不能完全看懂,文档中有一个例子。
微信消息内容
这一页都挺重要的,特别贴出来。消息内容 - itchat
命令行二维码显示
通过以下命令可以在登陆的时候使用命令行显示二维码:1
itchat.auto_login(enableCmdQR=True)
部分系统可能字幅宽度有出入,可以通过将,故赋enableCmdQR赋值为特定的倍数进行调整:1
2
3
4# 如部分的linux系统,块字符的宽度为一个字符(正常应为两字符)值为2
itchat.auto_login(enableCmdQR=2)
# 默认控制台背景色为暗色(黑色),若背景色为浅色(白色),可以将enableCmdQR赋值为负值:
itchat.auto_login(enableCmdQR=-1)
递归小结
关于递归
这几日作递归题,一直都没什么思路,常常需要看看答案才能懂
幸亏,答案看着看着,好像可以大概总结出一套模板:1
2
3
4
5
6
7
8def fun(arguments):
赋初值,定义容器
if conditions条件:
返回值,递归,改变参数,‘循环体’
(返回值处理)
return 返回值
else:
return 开始递归
典例:1
2
3
4
5
6
7
8def Bindec(x):
result = ' '
if x :
result = Bindec(x // 2)
return result + str(x % 2)
else:
return result
print("二进制数为:",Bindec(1024))
递归分为递推和回推,注意返回条件设置
总结出了模板,做题居然就不费劲了,我觉得主要是把上面的理论成功转化为了编程理论,所以思路顺畅了。
但模板还比较死,注意变通,如:
1 | # 拆分参数 |
这道题标答中并不像我返回并放好列表元素,它递归直接返回元素然后放入外部的列表中。但其实很多标答都和我的模板一样,只是了简化语句,大多是简化递推那部分,比如下例简短而有代表性:1
2
3if n != 1:
a = age(n-1)
return a + 2 #这两句可简化为一句:return age = (n-1)+2
PS:
list.insert()方法的返回值为空类型!
2018-1-7 17:49
最近做的文件处理题目,用到递归且比较独特,于是前来补充:
独特之处在于这种递归没有返回值,
如下是搜索返回文件的程序:
1 | import os |
2018-04-28
多年以后的现在,跟杜市容了解了一下一些算法的东西