程序员
董欣欣的个人博客

Java 判断浮点数相等(两直线是否相交)

阅读(555)评论(0)

计算机表示浮点数(float或double类型)都有一个精度限制,对于超出了精度限制的浮点数,计算机会把它们的精度之外的小数部分截断。因此,本来不相等的两个浮点数在计算机中可能就变成相等的了。

例子:

如果用“==”判断则结果是相等的。

所以判断浮点数是否相等时候不应该用==判断,可以使用Math.abs(a-b)结果判断

题目:给定一个函数,里面是两条直线斜率和截距,判断两直线是否相交

代码:

 

 

Java 锁Lock实例使用

阅读(720)评论(0)

synchronized和Lock区别:

synchronized:

(如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁)

获取锁的线程释放锁情况:

1、获取锁的线程执行完了该代码块,然后线程释放对锁的占有。

2、线程执行发生异常,此时JVM会让线程自动释放锁。

3、这个主要是在等待唤醒机制里面的wait()方法,在等待的时候立即释放锁,方便其他的线程使用锁。而且被唤醒时,就在此处唤醒。

虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,同时为了更好地释放锁。

锁对象Lock:

(通过Lock可以知道线程有没有成功获取到锁。这个是synchronized无法办到的)

1、Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问。

2、synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中。

3、在资源竞争不是很激烈的情况下,synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,synchronized的性能会下降几十倍。

Lock使用简单示例:(卖火车票例子)

测试方法:

 

 

 

 

高效的计算二进制1个数方法

阅读(533)评论(0)

普通方法:每位做&运算,然后右移

代码如下:

 

高效方法:数字a与(a-1)做&运算,直到a=0

代码如下:

实际操作时候会发现第二种要比第一种高效很多

Java 生产者消费者案例

阅读(591)评论(0)

生产者消费者:

简而言之,就是有一个公共资源类。生产者需要生产资源,消费者需要消耗资源。二者操作是同一变量,因此要保证生产者生产数量小于最大,消费者消耗时候必须保证变量是大于0的。同时保证二者访问时候要同步信息。否则就会出现不一致情况。

代码如下:

公共资源类:

生产者:

消费者:

测试类:

效果展示:(每一次运行结果都不同,注意资源数量是一致的)

Java 类加载器

阅读(757)评论(0)

类加载器

用来加载class字节码到Java虚拟机中的模块称为“类加载器”。

一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源文件在经过 Javac之后就被转换成 Java 字节码文件(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class 类的一个实例。

类与类加载器

对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟中的唯一性。说通俗一些,比较两个类是否“相等”,只有在两个类是由同一个类加载器的前提之下才有意义,否则,即使这两个类来源于同一个class文件,只要加载它的类加载器不同,那这两个类必定不相等。这里所指的“相等”包括代表类的Class对象的equal方法、isAssignableFrom()、isInstance()方法及instance关键字返回的结果。

类加载器分类

启动类加载器(Bootstrap ClassLoader)

扩展类加载器(Extention ClassLoader)

应用程序类加载器(Application ClassLoader)

自定义类加载器(User Defined ClassLoader)

启动类加载器(Bootstrap ClassLoader) C++实现

这个类加载器使用C++语言实现,并非ClassLoader的子类。主要负责加载存放在JAVA_HOME / jre / lib / rt.jar里面所有的class文件,或者被-Xbootclasspath参数所指定路径中以rt.jar命名的文件。

扩展类加载器(Extension ClassLoader) 基础类库

这个加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载AVA_HOME / lib / ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库。

应用程序类加载器(Application ClassLoader) classpath下类

这个加载器由sun.misc.Launcher$AppClassLoader实现,它负责加载classpath对应的jar及目录。一般情况下这个就是程序中默认的类加载器。

自定义类加载器(User Defined ClassLoader)

开发人员继承ClassLoader抽象类自行实现的类加载器,基于自行开发的ClassLoader可用于并非加载classpath中(例如从网络上下载的jar或二进制字节码)、还可以在加载class文件之前做些小动作 如:加密等。

双亲委派模型

上图中所展示的类加载器之间的这种层次关系,就称为类加载器的双亲委托模型。双亲委托模型要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器。这里类加载器之间的父子关系一般不会以继承的关系来实现,而是使用组合关系来复用父加载器的代码。

工作过程

如果一个类加载器收到了一个类加载请求,它首先不会自己去加载这个类,而是把这个请求委托给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成加载请求(它管理的范围之中没有这个类)时,子加载器才会尝试着自己去加载。

好处:安全、隔离

Java类随着它的类加载器一起具备了一种带有优先级的层次关系,例如java.lang.Object存放在rt.jar之中,无论那个类加载器要加载这个类,最终都是委托给启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类,相反,如果没有双亲委托模型,由各个类加载器去完成的话,如果用户自己写一个名为java.lang.Object的类,并放在classpath中,应用程序中可能会出现多个不同的Object类,java类型体系中最基本安全行为也就无法保证。

破坏双亲委派模型:非强制性约束

双亲委派模型并不是一个强制性的约束模型,而是推荐给开发者的一种类加载器实现方式。

应用:如热部署

判断一棵树是否是BST二叉查找树

阅读(559)评论(0)

题目:给定一个二叉树,判断是否是BST树 

此题目方法有很多种,这里讲解几种求解方法

思路:

1、中序遍历存在ArrayList里,遍历ArrayList确定是否是从小到大排序,如果是则即是BST树,否则不是

2、中序遍历不需要只需要遍历时候比较当前和上一个节点值

(遍历可以用递归也可以非递归用栈实现)

代码如下:

树的结构:

 

第一种:

第二种:

 

java继承初始化顺序(从jvm分析)

阅读(476)评论(0)

继承中初始化顺序:

从类的结构上而言,其内部可以有如下四种常见形态:属性(包括类属性和实例属性)、方法(包括类方法和实例方法)、构造器和初始化块(包括类的初始化块和实例的初始化块)。对于继承中的初始化顺序,又具体分为类的初始化和对象的初始化。

类的初始化:

在jvm装载类的准备阶段,首先为类的所有类属性和类初始化块分配内存空间。并在类首次初始化阶段中为其进行初始化,类属性和类初始化块之间的定义时的顺序决定了其初始化的顺序。若类存在父类,则首先初始化父类的类属性和类初始化块,一直上溯到Object类最先执行。

对象初始化:

在new创建对象时,首先对对象属性和初始化块分配内存,并执行默认初始化。如果存在父类,则先为父类对象属和初始化块先分配内存并执行初始化。

然后执行父类构造器中的初始化程序,接着才开始对子类的对象属性和初始化块执行初始化。

注意:

1、 在对象初始化阶段,属性和方法均针对子类可以从父类继承过来的属性和方法而言,一般而言,都是针对父类中非private而言的。

因为private修饰的为父类所特有的,子类没有继承过来,当new子类时,无须为其分配空间并执行初始化。当然了,父类的构造器子类也是不继承过来的,

但构造器另当别论。

2、类的初始化只执行一次,当对同一个类new多个对象时,类属性和类初始化块只初始化一次。

深入了解Java HashMap containsKey方法

阅读(1230)评论(0)

这里主要介绍下HashMap中 containsKey方法是如何实现的

containsKey方法源码如下:

前面一个条件是说两个对象的hashCode一样,后面一个条件是说两个类相等,这里对应Object类里的两个方法:getHashCode()和equals(),因此,要想使HashMap按照我们的意思去比较两个对象一不一样,不仅要重写equals方法,还要重写 getHashCode方法

注意:

HashCode相等,equals判断不一定相等

HashCode不等,equals判断一定不等

因此在重写相关方法时候,要保证这两点

java 死锁概念及实例

阅读(578)评论(0)

什么是死锁?

简单来说,死锁就是一个线程拿到第一把锁,继续执行代码时候还需要拿第二把锁,而第二个线程执行时候已经先拿走了第二把锁,且还需要拿第一把锁。此刻线程一需要等待第二把锁,线程二需要等待第一把锁,因此变成了互相等待的情况,导致了死锁的产生。(至少两个线程,两个资源,两个锁,这样才可以产生死锁。)

产生死锁实例如下:

注意:

1、两个线程等待对方锁的情况叫死锁,如果两个线程不是等待对方锁而是同时处于睡眠状态情况,不是死锁而是阻塞。

2、死锁的产生可以用sleep睡眠,但是不能用wait(),因为wait()休眠等待期间会释放对象的锁,这样就不会产生死锁。

3、非静态成员变量锁的实质是对象

Java 接口和抽象类

阅读(528)评论(0)

这里简单回顾下接口和抽象类区别:

– abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。

– 在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的。
– abstract class和interface所反映出的设计理念不同。其实abstract class表示的是”is-a”关系,interface表示的是”like-a”关系。
– 实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。
– 接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。
– 抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。
– 接口中的方法默认都是 public,abstract 类型的。

www.dongxinxin.cn 技术博客

联系我关于我