MyBatis 报错 - java.lang.IllegalArgumentException-invalid comparison-java.util.Date and java.lang.String

2019-06-23   龙德   MyBatis   MyBatis  

报错信息:

java.lang.IllegalArgumentException: invalid comparison: java.util.Date and java.lang.String 

错误原因:

原因是在 Mybatis 的 xml 文件里,加入了判断空字符串的语句,无法比较 java.util.Date 类型的字段与 java.lang.String 类型的 “”

<if test="node.createDate != null and node.createDate != ''">
    create_date,
</if>

解决方法:

将判断空字符串的语句删除

<if test="node.createDate != null">
    create_date,
</if>

java.lang.OutOfMemoryError PermGen space 的解决方法

2019-06-22   龙德   Java   OutOfMemoryError  

windows 环境,将项目部署到 tomcat,用 startup.bat 启动 tomcat,启动到一半,窗口就消失了。

这时候到 logs 目录下查看 catalina.xxx.log 文件,报了一个错:

java.lang.OutOfMemoryError: PermGen space

这是内存溢出的错误,可以通过设置启动参数来解决。

Java 是值传递还是引用传递

2019-06-19   龙德   Java   Java 值传递 引用传递  

传递基本类型

看看这段代码

public static void main(String[] args) {
	int a = 10;
	foo(a);
	System.out.println(a);
}
	
public static void foo(int x){
	x = 20;
}

运行代码,输出结果:10

可以看到将 a 当做参数传递给 foo() 后,a 的值并未改变。

因为变量 a 是基本类型,声明 a 相当于向内存申请了一块空间,这一块空间保存的值是 10。将 a 传递给 foo(),只是将 a 的字面量传递,相当于 x 复制了一份 a 的值,对 x 做任何操作,都不会影响到 a ,所以这是值传递

传递引用类型

先来看第一个例子

public static void main(String[] args) {
	Dog dog = new Dog("zhangSan");
	System.out.println(dog.getName());
	foo(dog);
	System.out.println(dog.getName());
}
	
public static void foo(Dog d){
	d.setName("Lisi");
}

输出结果:

zhangSan
Lisi

可以看到 “zhangSan” 这条狗的名字改变了,变成了 “Lisi”,是不是就认为这是引用传递了呢?

当然不是的!

问题出现在这

Dog dog;

当你编写该定义时,你定义的是 Dog 类型的引用(这个引用保存在栈中),并不是 Dog 对象本身,如果你此时向 dog 发送一个消息,就会返回一个空指针异常。这是因为 dog 实际上并没有与任何事物相关联。

当你希望 dog 与一个新的对象相关联时,通常用 new 操作符来实现。

Dog dog = new Dog("zhangSan");

new 操作符在堆中创建了名为 “zhangSan” 的 Dog 对象,并将地址值(假如是 0x00)保存在名为 dog 的引用中,这样 dog 就指向了在堆中的对象,这时候使用 dog 就能向对象发送消息了。

再看下面这个例子

public static void main(String[] args){
    Dog dog = new Dog("zhangSan");
    Dog oldDog = dog;
    foo(dog);
    System.out.println(dog.getName());
    System.out.println(dog == oldDog);
}

public static void foo(Dog d){
    d = new Dog("Lisi");
}

输出结果:

zhangSan
true

将 dog 传递给 foo() 后,在 foo() 里 把它指向另一个新的对象,如果是引用传递,那么 dog 这个引用就应该重新指向这个新对象,但是从输出结果来看这是错误的。

原因是传递给 foo() 的,并不是 dog 这个引用本身,而是它所指向的在堆中对象的地址值。假如这个地址值是 0x00,那么可以这样理解,传递给 foo() 的,是 0x00。

我们在 foo() 里接受到这个地址值 0x00 后,可以给 0x00 所指向的对象发送消息,操作这个对象。形参 d 将对象的名字设置为 “Lisi” 后,dog 取出对象的名字也是 “Lisi”,这正如第一个例子所示。也就是说 d 这个形参和 dog 这个实参指向的是同一个对象,都保存着同一个地址值(0x00)。

但是将形参 d 重新指向另一个新对象,并不会对实参 dog 有任何影响,dog 还是仍然指向 0x00 这个地址值。

所以结论是,将 dog 传递给 foo(),并不是将引用本身传递,而是将引用所指向的地址值传递,也就是值传递

结论

无论是传递基本类型还是引用类型,都是值传递

参考资料

https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value?r=SearchResults

http://www.javadude.com/articles/passbyvalue.htm

Java 设计模式-观察者(发布-订阅)模式

2019-06-18   龙德   Java   Java 设计模式 观察者模式  

观察者模式简介

观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

在观察者模式中有如下角色:

==Subject==:抽象主题(抽象被观察者)

接口实现,规定了增加订阅者、删除订阅者、发布主题的基本方法。

==ConcreteSubject==:具体主题(具体被观察者)

抽象主题接口的实现类,该类保存具体的订阅者(观察者)对象,当发布主题时通知订阅者去更新。

==Observer==:抽象观察者

接口实现,规定了订阅主题,取消订阅、更新主题的基本方法

==ConcrereObserver==:具体观察者

抽象观察者的实现类,当收到主题的通知时更新以获取到主题。

Java-类继承的抽象类和实现的接口有相同的方法签名

2019-06-17   龙德   Java   Java  

抽象类的抽象方法跟接口的方法相同

抽象类

public abstract class APerson {

	public abstract void speak();
}

接口

public interface IPerson {

	void speak();
}

子类

public class ZhangSan extends APerson implements IPerson {

	@Override
	public void speak() {
		System.out.println("haha");
	}

	public static void main(String[] args) {
		ZhangSan zhangSan = new ZhangSan();
		zhangSan.speak();
	}
}

IDEA 去掉 xml、jsp、js 文件的屎黄色和淡绿色

2019-06-15   龙德   杂七杂八   IDEA  

如图,一堆的屎黄色实在是不好看

image

SpringBoot 项目为什么没有 web.xml

2019-06-11   龙德   SpringBoot   SpringBoot web.xml  

前言

我们在开发 SpringMVC 项目时,都会在 web.xml 里配置 listener、servlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" metadata-complete="true" version="3.1">
  
  <!-- 因为配置了spring的ContextLoderListener监听器,所以需指定spring核心文件的位置 ,
 	       否则默认加载/WEB-INF/applicationContext.xml这个文件-->
  <context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring/spring-*.xml</param-value>
  </context-param>
  
   <!-- Spring监听器 -->
  <listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  
  <servlet>
    <servlet-name>springMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring/spring-*.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springMVC</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
 
</web-app>

SpringBoot 的出现极大的简化了我们的开发流程,细心地同学可能会发现,SpringBoot 是没有 web.xml 的,那么 Servlet、 Filter 和 Listener 等繁琐的 web 的相关配置,SpringBoot 是用什么替代的呢?

这个问题不难回答,Servlet、Filter 和 Listener 并不会凭空的帮我们自动配好,SpringBoot 既然抛弃了 web.xml,那么它肯定是在代码里提供了配置功能的类。

其实开发一个 Java Web 项目,不用 web.xml 配置,并不是 SpringBoot 开创的新特性。早在 Serlvet3.0 之后,我们开发一个 Java Web 项目就可以不用 web.xml 配置了,而 SpringMVC 又是基于 Servlet 的,所以要弄清楚 SpringBoot 是用什么替代 web.xml 的,得先从 Servlet 说起。

Java 动态代理

2019-06-07   龙德   Java   动态代理  

引言

动态代理是 Java 技术中最重要的一点,如果不会动态代理,那么在学习 Spring、MyBatis 等框架的源码时是学不明白的!

代理的概念

动态代理简单来说就是动态的产生一个代理对象,代理对象会负责将所有的方法调用分派到委托对象上反射执行。

举一个生活中的例子:一个人还没有出名时,如果想找他唱歌跳舞,那就直接找他本人就完事了。但是当他出名后,成了明星,就不能直接找他唱歌跳舞了,得找他的经纪人来沟通。比如刘德华,他是一个非常出名的明星,会唱歌,会跳舞。如果你想找他唱歌跳舞,刘德华(被代理类)就会说,你先去找我的经纪人(代理类)吧。所以你这时只能去找经纪人了,因此这个经纪人就拦截了我们对刘德华的直接访问。

所以现实生活中的例子跟我们开发是一样的,我们在开发时,产生一个代理对象,拦截对被代理对象的访问,并做出相应的业务处理。

微服务入门-SpringBoot+Dubbo搭建一个简单的 Maven 多模块的 Demo

2019-06-03   龙德   杂七杂八   微服务 SpringBoot Dubbo Maven  

微服务

微服务就是将一个完整的系统,按照业务功能,拆分成一个个独立的子系统,在微服务结构中,每个子系统就被称为“服务”。这些子系统能够独立运行在 web 容器中,它们之间通过 RPC 方式通信。

Dubbo

Dubbo 是一款高性能 Java RPC 框架,也叫微服务系统的协调者。在它这套体系中,一共有三种角色,分别是:服务提供者(provider)、服务消费者(consumer)、注册中心(zookeeper)。

服务提供者启动时,向注册中心注册自己提供的服务。服务消费者在启动时,向注册中心订阅自己所需的服务。注册中心返回服务提供者地址列表给消费者。此时消费者调用提供者提供的服务时,就跟在本地调用一样。

本文只是一个入门的 Demo,更多的 Dubbo 原理不在本文阐述范围内。

pom.xml错误:org.codehaus.plexus.archiver.jar.Manifest.write(java.io.PrintWriter)的解决方法

2019-05-30   龙德   杂七杂八   Maven pom.xml  

pom.xml 文件在添加了新的依赖后,一直报:org.codehaus.plexus.archiver.jar.Manifest.write(java.io.PrintWriter) 的错误,Maven Update 后依然如此。

我用的 Eclipse 是 Eclipse Neon (4.6)版本,自带 Maven 插件。

更新eclipse中的maven插件方法如下:

点击:help -> Install New Software -> add -> http://repo1.maven.org/maven2/.m2e/connectors/m2eclipse-mavenarchiver/0.17.2/N/LATEST/

一直下一步即可。

image