0%

概要:今天想运用一下已学的知识试着实现一下微信的聊天界面。主要实现的功能只是聊天内容的发送和显示。
这其实是《第一行代码》中的一个实战样例,主要想记录一下心得体会。

阅读全文 »

引入

今天打开android studio发现屏幕上星星点点全是标红,一般gradle未build完成会出现这个情况所以我还是很淡定的。但是gradle建立完还是标红,但是run一切正常。仔细查看发现是有几个package导入失败了,原因是未找到。所以只能google。
得到以下结果。


首先出现问题的话,肯定要rebuild project、重启andriod studio都先试一遍,甚至重启电脑、从SVN下载重新导入,因为android studio其实还是有些bug。

阅读全文 »

Java可变参数

在java方法定义是可以使用个数不确定的参数,对于同一个方法可以用不同个数的参数调用。

1. 定义方法

…表示可变参数
在有可变参数的方法中可以把参数当做数组使用。

阅读全文 »

今天学长出了一道题,我发现我竟然对初始化代码块的存在一无所知。
初始化代码块(initialization block)是初始化数据域的第三种机制(前两种分别是构造器和声明时赋值)。只要构造类的对象,只写代码块就会被自动执行,不需要调用。

1
2
3
4
5
6
7
8
9
10
11
class A
{
//数据域
private int id;
private int name;
//object initilization block
{
id = 4;
name++;
}
}

构造类时,先运行初始化代码块,再运行构造方法的主体。
注:
为了避免循环定义,不要读取初始化以后的域
Java是按照编程顺序来执行实例变量初始化器和实例初始化器中的代码的,并且不允许顺序靠前的实例代码块初始化在其后面定义的实例变量
对静态域进行初始化,可直接提供一个初始化值(private ststic int id = 1;),也可通过静态的初始化块进行初始化。
1
2
3
static{

}

再类第一次加载时,即进行静态域的初始化。且所有的静态初始化语句与静态初始化块都将按类的定义顺序执行。
注:
JVM加载类时执行(仅执行一次)

  1. 随类的加载执行,只执行一次,并优先于主函数main。
  2. 静态代码初始化块是给类初始化,构造代码块是给对象初始化。
  3. 静态代码块中的变量是局部变量,等同于普通函数中的局部变量。
  4. 一个类中可以有多个静态代码块。

当涉及到继承时,按照如下顺序执行:
执行父类的静态代码块,初始化父类静态成员变量
执行子类的静态代码块,初始化子类静态成员变量
执行父类的构造代码块,执行父类的构造函数,初始化父类普通成员变量
执行子类的构造代码块,执行子类的构造函数,初始化子类普通成员变量

hexo image

I.

1
2
3
4
5
int a;
{
b = a;
}
int b;

II.
1
2
3
4
5
int b; 
{
b = a;
}
int a;

I能够通过编译,但II报错:非法前引用。

静态代码块只能对其之前的数据进行访问,对于其之后的数据可以赋值但不能被访问。
—《深入理解Java虚拟机》

总结:
调用构造器的具体处理步骤:

  1. 所有数据域被初始化为默认值(0,false,null)
  2. 按类声明的顺序执行 与初始化语句和初始化
  3. 若构造器首行调用了第二个构造器,则执行第二个构造器主体
  4. 执行构造器

一个Java对象的创建过程往往包括类初始化和类实例化两个阶段,类实例化包括实例变量初始化、实例代码块初始化以及构造函数初始化

实际上,如果我们对实例变量直接赋值或者使用实例代码块赋值,那么编译器会将其中的代码放到类的构造函数中去,并且这些代码会被放在对超类构造函数的调用语句之后,构造函数本身的代码之前

实例化对象时,JVM首先会检查相关类型是否已经加载并初始化,如果没有,则JVM立即进行加载并调用类构造器完成类的初始化。在类初始化过程中或初始化完毕后,根据具体情况才会去对类进行实例化。

其实一般也很少使用到初始化块,因为都是在构造方法内完成类的初始化。初始化块一般适用于加载类时加载本地库。

Git

因为经常会要用到Git以及Github,首先安装Git:https://git-scm.com/download/linux

1
$ 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
2
node -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
2
npm config set unsafe-perm true       //以后,再运行
npm install -g hexo-cli //但是我好像没有遇到这个问题。

我的话主要是教程里都没有提醒我创建hexo的全局变量,导致我一直显示未找到命令。创建了变量后就成功了。这里用
1
hexo -v

若出现版本信息,则安装成功,已在本地机器上搭建起了Hexo环境。

部署Hexo文件夹。

任意位置创建文件夹hexo,在该文件夹内初始化hexo

1
2
hexo 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
4
server:
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
2
git 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
4
deploy:
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
8
hexo g -d
hexo g 为生成静态文件
hexo g -d 为文件生成后立即部署网站
或者hexo g 然后hexo d也行
hexo d -g 为部署网站前生成静态文件

git push [-u origin master] 仓库数据进行同步
git pull 每次修改前进行更新

编写博客
1
2
3
hexo 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拉取。

静态列表与动态列表

  1. 静态列表:所有结点都是在程序中定义。
  2. 动态列表:所有结点临时开辟,用完释放,即一个个开辟结点并输入节点的值,建立前后连接关系。

    -> : 指向运算符

    1
    p -> next        <=>        (*p)next 
  • 指向结构体的指针不指向结构体成员,因为类型不同
  • 定义动态链表,需要约定好链表结束的条件。
  • 动态链表: 让p1指向新开辟的结点,p2指向链表最后一个结点,把p1所指的结点连接在p2所指的结点后面。
  1. 用malloc开辟结点1(n=1),使p1指向它。
    1
    p1 = (struct Name *) malloc (Name长度); 
  2. 输入节点数据;
  3. 链入结点2(n=2),p1的值赋给p2 -> next,此时p2指向第一个节点,故 p2 -> next = p1 将结点2的地址赋给结点1的 next;
  4. 使 p2 = p1,即使p2指向新结点。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    struct 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;
    }
    在建立链表的循环中,例1是
  • 连接
  • 创建
  • 赋值(此时p2在旧结点p1在新结点

例1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct Student* creat()
{
struct Student *p1, *p2, *head;
head = (struct Student *)malloc(Len);
p1 = p2 = head;
scanf("%d%d",&(*p1).id, &(*p1).age);
do
{
p1 = (struct Student *)malloc(Len);
(*p2).next = p1;
p2 = p1;
scanf("%d%d",&(*p1).id, &(*p1).age);
}
while((*p2).id != 0);
(*p1).next = NULL;
return head;
}

在建立链表的循环中,例2是

  • 创建
  • 链接
  • 赋值(此时p2与p1都在新结点

例2

关于itchat的学习体验

pip模块下载

在控制台窗口用pip install下载,并用

1
pip list

查看,已载入。在python-Shell下始终无法导入。后来改用命令pip3 install安装成功。pip3 list已载入,再导入,成功!

itchat初体验

  1. 获取网页登陆的二维码
    1
    itchat.auto_login( )
  2. 发信息
    1
    itchat.send
    1
    itchat.search_friends(name = u"备注名称或昵称")  #获取对方的全部信息(列表)
    列表中只有一个元素,是一个字典,引索”UserName”得到微信号,是一长串十六进制的数字
    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
6
import 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.xlsx
1
2
3
itchat.send('@img@%s' % 'gz.gif')                  #识别为发送图片
itchat.send('@fil@%s' % 'xlsx.xlsx') #识别为发送文件
itchat.send('@vid@%s' % 'demo.mp4') #识别为发送视频

其他:
1
2
3
4
send_msg(msg='Text Message', toUserName=None)
send_file(fileDir, toUserName=None)
send_img(fileDir, toUserName=None)
send_video(fileDir, toUserName=None) #需保证发送视频为一实质的mp4文件

注册消息方法

itchat将根据接收到的消息类型寻找对应的已经注册的方法。如果一个消息类型没有对应的注册方法,该消息将会被舍弃。在运行过程当中也可以动态注册方法,注册方式与结果不变。

不带具体对象注册,将注册为普通消息的回复方法
1
2
def simple_reply(msg):
return 'I received: %s' % msg['Text']

带对象参数注册,对应消息对象将调用该方法

1
2
3
@itchat.msg_register(TEXT, isFriendChat=True, isGroupChat=True, isMpChat=True)
def text_reply(msg):
msg.user.send('%s: %s' % (msg.type, msg.text))

注册消息的优先级

优先级分别为:后注册消息先于先注册消息,带参数消息先于不带参数消息

1
2
3
from itchat.content import *
@itchat.msg_register
@itchat.msg_register(TEXT)

看了这个例子,我也终于懂了itchat处理信息的机制。@msg_register方法注册信息类型,其后定义函数来表明处理该类信息的方法。
尝试打印
1
2
3
4
search_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
23
import 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
8
def fun(arguments):
赋初值,定义容器
if conditions条件:
返回值,递归,改变参数,‘循环体’
(返回值处理)
return 返回值
else
return 开始递归

典例:
1
2
3
4
5
6
7
8
def Bindec(x):
result = ' '
if x :
result = Bindec(x // 2)
return result + str(x % 2)
else:
return result
print("二进制数为:",Bindec(1024))

递归分为递推和回推,注意返回条件设置

总结出了模板,做题居然就不费劲了,我觉得主要是把上面的理论成功转化为了编程理论,所以思路顺畅了。

但模板还比较死,注意变通,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 拆分参数
def get(x):
result = list()
if x:
result = get(x // 10)
result.append(x % 10)
return result
else:
return result
#简单版
result = list()
def simple(x):
if x:
result.insert(0, x%10)
simple(x//10)
i = int(input("输入一个数:"))
print(get(i)) ;
simple(i) ;
print(result)

这道题标答中并不像我返回并放好列表元素,它递归直接返回元素然后放入外部的列表中。但其实很多标答都和我的模板一样,只是了简化语句,大多是简化递推那部分,比如下例简短而有代表性:

1
2
3
if n != 1:
a = age(n-1)
return a + 2 #这两句可简化为一句:return age = (n-1)+2

PS:

list.insert()方法的返回值为空类型!



2018-1-7 17:49

最近做的文件处理题目,用到递归且比较独特,于是前来补充:

独特之处在于这种递归没有返回值

如下是搜索返回文件的程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
import os
def found(file, folder):
os.chdir(folder)
l1 = os.listdir(os.getcwd())
for each in l1:
if os.path.isdir(each):
found(file, each) #继续执行函数但注意细节,如这里当前文件目录已经在递归过程中改变,需回位!!
os.chdir('..')
elif each == file:
print(os.getcwd() + os.sep + file) #到递归底层打印结果,无返回值,直接开始回推
folder = input('请输入待查找的初始目录:')
file = input('请输入目标文件:')
found(file, folder)

2018-04-28
多年以后的现在,跟杜市容了解了一下一些算法的东西