不知道大家有没有对.java文件进行编译之后生成的.class文件好奇过。 我们都知道Java中的class文件是经过Java编译器对Java类文件进行编译后的产物。我想有不在少数的C程序员在学习Java之后在认知上会粗略的认为C程序在经过编译后产生的.out文件与.class文件在各方面大概相同,我刚开始也这样迷惑自己,但是随着学习的深入,我们必须搞清楚.class文件到底是个什么东西。 那么今天我就为大家来分享一下Java中的.class文件到底是什么,它里面到底存储了哪些内容~ 对了,如果你用IDEA这种环境集成开发工具来查阅.class文件的话,会发现它和源代码并没有什么区别,因为它将.class文件顺便进行了反编译。 .class文件和.out文件的不同 要想明白两个文件的不同,我们首先要了解两个文件的定义。 .class文件 java的编译器在编译java类文件时,会将原有的文本文件(.java)翻译成二进制的字节码,并将这些字节码存储在.class文件。 也就是说java类文件中的属性、方法,以及类中的常量信息,都会被 继续阅读 >>


董恒毅 17/10/20 23:50:16
useradd命令 useradd 选项 用户名 -d 目录,指定用户主目录,如果此目录不存在,则同时使用-m选项,可以创建主目录。 -g 用户组,指定用户所属的用户组。 -G 用户组,指定用户所属的附加组。 -s Shell文件,指定用户的登录Shell。 -u 用户号,指定用户的用户号,如果同时有-o选项,则可以重复使用其他用户的标识号。 例1: # useradd –d /home/sam -m sam 添加了一个用户sam,并且他的主目录为/home/sam,没有主目录的时候自动创建。(/home为默认的用户主目录所在的父目录) 例2: useradd -s /bin/sh -g group –G adm,root gem 添加一个用户gem,使用的Shell是/bin/sh,主用户组为group,附加组为adm,root。 userdel命令 userdel 选项 用户名 -r 把用户的主目录一起删除。 usermod命令 usermod 选项 用户名 例 继续阅读 >>


董恒毅 17/10/20 11:46:02
先说点题外话吧,在我刚开始学习爬虫的时候,有一次一个学长给了我一个需求,让我把京东图书的相关信息抓取下来。恩,因为真的是刚开始学习爬虫,并且是用豆瓣练得手,抓取了大概500篇左右的影评吧,然后存放到了mysql中,当时觉得自己厉害的不行,于是轻松的接下了这个需求。。。 然后信心满满的开始干活。。首先查看网页源代码。。。???我需要的东西源代码里面没有!!!然后去问了学长。学长给我说,这是AJAX产生的数据,大概听完之后我就去查了资料。发现网上大片的资料都在阐述一个道理,对于动态页面,使用PhantomJs进行抓取,但是这样效率很低。作为一个优秀的程序员,当时看见效率很低这四个字,那在我心里是绝对不能被允许的,所以我就采用了抓包的方式,查看AJAX数据所在的URL,对于这个模拟浏览器的方法也就一直搁置到现在。 但是既然知道了这个东西,哪有不去学习的道理。所以我抽出了一点时间看了一下关于Java方面使用PhantomJs的资料,现在分享给大家。 对了,其实做网络爬虫,页面上90%的数据都可以使用抓包进行获取。所以我还是鼓励大家直接请求自己所需数据所在的URL 继续阅读 >>


董恒毅 17/10/10 22:29:57
最近打算通过学校的某某系统抓取一下每个学生的个人信息,由于需要进行模拟登录,所以就要对登录页面进行post参数的提交。但是在进行网络抓包的过程中,使用chrome自带的网络抓包分析工具(也就是F12)发现每次在进行登录提交表格之后,chrome并不能将所需要提交的参数表单抓取下来。 问了学长原因,觉得是登录成功之后因为页面的跳转需要进行刷新,所以就将表单提交的那部分数据给刷掉了。学长提供的解决办法是使用fiddler网络抓包工具进行抓包及分析。但在查阅相关资料之后发现fiddler对Linux操作系统(本人开发环境Ubuntu 16.04)的支持并不是很好。所以我使用了tcpdump进行网络抓包,结合wireshark进行数据包的分析。 需求如下: 如图,提交登录表单的页面,然后使用chrome自带抓包工具进行网络抓包: 这里面并没有我想要的东西。 tcpdump的使用 tcpdump [-i 网卡] -nnAX ‘表达式’ 各参数说明如下: -i:interface 监听的网卡。 -nn:表示以ip和por 继续阅读 >>


董恒毅 17/09/24 16:00:03
作为被面试官最喜欢问到的23种设计模式之一,我们不得不熟练掌握单例模式以及洞悉多线程环境下,单例模式所存在的非线程安全问题以及它的解决方式。 注:这篇文章主要讲述多线程环境下单例模式存在的非线程安全问题,并不详细讲述单例模式。 何为单例模式 首先我们先大概了解一下单例模式的定义: 单例类只能有一个实例。 单例类必须自己创建自己的唯一实例。 单例类必须给所有其他对象提供这一实例。 单例模式的应用非常广泛,例如在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。选择单例模式就是为了避免不一致状态。 单例模式的实现有三种方式:饿汉式(天生线程安全),懒汉式,登记式(可忽略)。 对于上面单例模式的实现方式我在这里不做过多介绍,我们着重来看一下懒汉式在多线程环境下出现的问题以及它的解决策略。 设计线程安全的单例模式 D 继续阅读 >>


董恒毅 17/08/29 14:14:58
在上一篇博客JVM–解析Java内存区域及数据的内存分配与线程安全之间的一些联系中也说到了,想要理解volatile关键字,我们需要掌握Java虚拟机运行时数据区的相关知识,但是这还不够,只有理解了Java的内存模型,我们才能开始讲述volatile,而Java虚拟机运行时数据区是掌握Java内存模型的基础,所以如果你还没有看上一篇博客,请点击上方链接~~~ 引言 既然本节讲述volatile关键字,那么就先抛个砖引个玉(以下代码在64位jdk1.8下进行测试,不同jdk版本运行结果有可能不一样): public class RunThread implements Runnable { private boolean isRunning = true; public boolean isRunning() { return isRunning; } public void setRunning(boolean isRunning) { this.isRunning = isRu 继续阅读 >>


董恒毅 17/08/16 09:39:38
一直觉得自己之前写的使用定时抓取构建IP代理池实在过于简陋,并且有一部分的代码写的并不合理,刚好最近又在学习多线程,就将之前的代码进行了重构,也方便对抓取代理ip有需求的人。之前自己写的那篇文章就不删除了,里面用到了MySQL以及循环调用ip的方法(一些东西也是值得了解的。取其精华,弃其糟粕吧),大家有兴趣的可以看一下(最主要的还是不舍得访问量,哈哈)。 注:由于xici代理网的ip代理并不是很稳定,所以自己实现的ip代理池并不可用(4000个IP最后通过一系列逻辑处理和过滤之后大概只剩30多个,并且这30个ip也极不稳定),但感觉实现ip代理池的原理就是这样,在往后估计也就是性能上的优化。虽然ip代理池并不可用,但是如果你想要学习多线程以及抓取ip做爬虫的话,这篇文章我觉得是可以给你一些思路上的启发。 怎么设计一个IP代理池 其实设计一个IP代理池是非常容易的一件事情,我们来看一下其中的步骤: 1.首先肯定是从提供代理ip的网站上对ip进行抓取 2.对抓取下来的ip进行初步的过滤,比如我一开始就将IP类型不是HTTPS并且IP链接 继续阅读 >>


董恒毅 17/08/10 17:16:02
最近一直在看《Java多线程编程核心技术》的第二章,主要讲的是线程共享变量与线程私有变量以及如何写出线程安全的代码。看这部分一开始没太注意,只是记住了一条规则,“类中的成员变量,也叫实例变量,也叫全局变量,它是非线程安全,是所有线程共享的变量,定义在方法中的私有变量是线程安全的,是每个线程私有的”。很好理解不是吗,然后一帆风顺的看到了关于volatile这部分的知识,看过之后我陷入了凌乱。。。关于这部分我之后进行总结,而现在我觉得你如果真的想写出线程安全的代码,那么Java的内存分配以及布局就是我们需要掌握的基础。为此,我粗略的看了一下《深入理解Java虚拟机》这本书的第二章,并且查阅了一些资料,现在汇总整理如下。 注:学习这部分内容之前如果你对进程的内存映像或数据在内存中的分配有大概的了解,建议你先忘记它们,因为这是讲Java虚拟机运行时的数据区,和之前的知识并不相同,所以学习的时候不要拿自己以前所了解的知识进行比较与衡量。 Java虚拟机运行时的数据区 先来看一张图片: 在这里我们只需要关注线程共享区中的堆,以及线程独占区中的虚拟机栈, 继续阅读 >>


董恒毅 17/08/08 14:26:58
注:本系列博客参考《Java多线程编程核心技术》,主要是对书上的知识点进行总结,并记录学习过程。 一直对并发这块比较感兴趣,也到了系统学习Java多线程的时间。目前所学习的书籍是《Java多线程编程核心技术》,买回来之后听说这本书不怎么样,豆瓣评分也就7点几,目前读完了第一章,感觉确实不是很好,但是也不算太坑,总的来说还是可以入手的。好了,废话不多说,开始正题。 首先我们来看一份代码: public class CountOperate extends Thread { public CountOperate() { out.println("CountOperate---begin"); out.println("Thread.currentThread.getName()=" + Thread.currentThread().getName()); out.println("this.name()=" + this.getName()); out.println("Thr 继续阅读 >>


董恒毅 17/08/04 10:15:20
为什么我们需要掌握这些“高端”的树型结构 事实上,大型数据库的组织结构一般采用树型结构,我们必须要解决频繁更新数据的能力,要求支持高效的动态查找能力,包括记录的插入,删除,精确匹配查询,范围查询和最大值、最小值查询。但是由于数据库中包含了大量的记录,所以线性表的查询本身会因为记录太大而无法存储到主存之中,另外对于记录的插入和删除操作更需要移动大量的元素,这本身的效率是非常低下的。 二叉查找树(BST)的定义 二叉查找树要么是一颗空树,要么满足以下的定义: 若它的左子树不为空,那么它左子树上所有节点的值均小于等于根节点 若它的右子树不为空,那么它右子树上所有节点的值均小于根节点 它的左右子树均是二叉查找树 这明显是一个递归定义,因此我们对于BST的操作大多是建立在递归之上的。 二叉查找树有一个重要的特征:对一颗二叉查找树进行中序遍历,可以得到一个递增序列,那么我们只要将中序遍历的遍历顺序反过来,那么我们就会得到一个递减序列,这也正是二叉查找树得名的原因。 BST的数据结构 typedef int 继续阅读 >>


董恒毅 17/08/03 10:16:00