java注意的一些细节问题
1. 大括弧作用域问题
public static void main(String[] args) { { int x; { int x;//编译错误:Duplicate local variable x } } }
2.boolean值的运算
public static void main(String[] args) { if(true && false) {} if(true & false) {} System.out.println(true & false); System.out.println(true ^ false); System.out.println(true | false); }
false
true
true
3.continue label 和 break label
public static void main(String[] args) { label: for(int i=0; i<2; ++i){ System.out.println("i=" + i); for(int j=0; j<3; ++j){ if(j == 1){ //continue; //break; //continue label; break label; } System.out.println(" j=" + j); } } }
这个例子中,continue label和break具有同样的作用。
public static void main(String[] args) { label: for(int k=0; k<2; ++k){ System.out.println("k=" + k); for(int i=0; i<2; ++i){ System.out.println(" i=" + i); for(int j=0; j<3; ++j){ if(j == 1){ //break; continue label; } System.out.println(" j=" + j); } } } }
这个例子就更加直观的看到 continue label实现不一样的效果!
4.基本类型和对应对象分别做参数的函数重载
class A{ public void fun(int x){ System.out.println("int 重载"); } public void fun(Integer x){ System.out.println("Integer 重载"); } } public class Main{ public static void main(String[] args) { A a = new A(); int x = 1; Integer ix = 1; a.fun(x); a.fun(ix); } }
int 重载
Integer 重载
5.获取绝对路径
request.getSession().getServletContext() 获取的是Servlet容器对象,相当于tomcat容器了。getRealPath("/") 获取实际路径,“/”指代项目根目录,所以代码返回的是项目在容器中的实际发布运行的根路径。
ClassLoader类的getResource(String name),getResourceAsStream(String name)等方法,使用相对于当前项目的classpath的相对路径来查找资源。
1.jsp页面
String path = pageContext.getServletContext().getRealPath("/");
或者 String path = request.getSession().getServletContext().getRealPath("/");
String realPath = path+"/WEB-INF/classes/abc.properties";
2.java 程序
InputStream in = getClass().getClassLoader().getResourceAsStream("abc.properties"); // abc.properties放在webroot/WEB-INF/classes/目录下
推荐使用Thread.currentThread().getContextClassLoader().getResource("")来得到当前的classpath的绝对路径的URI表示法。
prop.load(in);
in.close();
3.只通过Java程序操作资源文件
InputStream in = new FileInputStream("abc.properties"); // 相对路径,项目下的路径
OutputStream out = new FileOutputStream("abc.properties");
6.异常链
public class Main{ public static void test2(){ throw new NullPointerException("空指针异常!"); } public static void test() throws Exception{ try{ test2(); } catch (Exception e){ //throw new Exception("自定义异常!"); //(1) throw new Exception("自定义异常!", e);//(2) } } public static void main(String[] args) { try{ test(); } catch(Exception e) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); System.out.println(sw.toString()); } } }
注意:(1)和(2)的输出差别
(1)java.lang.Exception: 自定义异常! at com.hjzgg.Main.test(Main.java:28) at com.hjzgg.Main.main(Main.java:34) (2)java.lang.Exception: 自定义异常! at com.hjzgg.Main.test(Main.java:29) at com.hjzgg.Main.main(Main.java:35) Caused by: java.lang.NullPointerException: 空指针异常! at com.hjzgg.Main.test2(Main.java:21) at com.hjzgg.Main.test(Main.java:26) ... 1 more
7.web中一些地址信息
1).地址栏输入:http://localhost:8080/HJZGG_BLOG/pictureAction!pictureGroupJspGetAllGroups
System.out.println(ServletActionContext.getServletContext().getRealPath("/savePath"));
System.out.println(ServletActionContext.getRequest().getServletPath());
System.out.println(ServletActionContext.getRequest().getRequestURL());
System.out.println(ServletActionContext.getRequest().getRequestURI());
打印的结果如下:
F:\eclipseEE_workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\HJZGG_BLOG\savePath
/pictureAction!pictureGroupJspGetAllGroups
http://localhost:8080/HJZGG_BLOG/pictureAction!pictureGroupJspGetAllGroups
/HJZGG_BLOG/pictureAction!pictureGroupJspGetAllGroups
2).得到完整的URL请求
访问:http://localhost:8080/HJZGG_BLOG/pictureAction!pictureGroupJspGetAllGroups
HttpServletRequest request;
String url = null;
url = request.getScheme()+"://" //请求协议 http 或 https
+ request.getServerName() //服务器地址
+ ":"
+ request.getServerPort() //端口号
+ request.getContextPath() //项目名称
+ request.getServletPath() //请求页面或其他地址 ,例如:pictureAction!pictureGroupJspGetAllGroups
+ "?" + (request.getQueryString()); //参数
System. out.println(url);
输出:http://localhost:8080/HJZGG_BLOG/pictureAction!pictureGroupJspGetAllGroups?null
3).得到项目根目录的URL
HttpServletRequest request = ServletActionContext.getRequest();
String url = null;
url = request.getScheme()+"://" //请求协议 http 或 https
+ request.getServerName() //服务器地址(可以替换成 InetAddress.getLocalHost().getHostAddress())
+ ":"
+ request.getServerPort() //端口号
+ request.getContextPath(); //项目名称
System. out.println(url);
输出:http://localhost:8080/HJZGG_BLOG
8.内部类和内嵌口
//如果外部类返回是 private类型的内部类,非此外部类的其他方法不能访问这个内部类 class A{ private class B{ public void fun(){} } public B getBInstance(){ return new B(); } public void invokeBMethod(B b){ b.fun(); } private int x; public int getX(){ return x; } } //内嵌接口, 如果你不想将你的借口暴露给外部,写成如下方式,否则将内嵌接口定义成 public,或者将接口写成非内嵌接口的形式 class C{ interface E{ void gun(); } private interface D { void fun(); } private class DImpl implements D{ @Override public void fun() {} } public D getDImpl(){ return new DImpl(); } public void invokeDMethod(D d){ d.fun(); } } //内部链接提供给外部 interface H{ void fun(); } class I{ private class G implements H{ @Override public void fun() {} } public H getHImpl(){ return new G(); } } class F implements C.E{ @Override public void gun() {} } public class Main{ public static void main(String[] args) { A a = new A(); int x = a.getX(); //error, The type A.B is not visible //a.getBInstance().fun(); a.invokeBMethod(a.getBInstance()); C c = new C(); //error, The type A.B is not visible // c.getDImpl().fun(); c.invokeDMethod(c.getDImpl()); H h = new I().getHImpl(); h.fun(); } }
9.协变类型
java中泛型是不变的,可有时需要实现逆变与协变,怎么办呢?这时,通配符?
派上了用场:
<? extends>
实现了泛型的协变,比如:
List<? extends Number> list = new ArrayList<Integer>();
<? super>
实现了泛型的逆变,比如:
List<? super Number> list = new ArrayList<Object>();
class Parent{ public Parent getSelf(){ return new Parent(); } } class Child extends Parent{ @Override public Child getSelf(){ return new Child(); } }
在Java1.4及以前,子类方法如果要覆盖超类的某个方法,必须具有完全相同的方法签名,包括返回值也必须完全一样。
Java5.0放宽了这一限制,只要子类方法与超类方法具有相同的方法签名,或者子类方法的返回值是超类方法的子类型,就可以覆盖。
注意:"协变返回(covariant return)",仅在subclass(子类)的返回类型是superclass(父类)返回类型的extension(继承)时才被容许。
10.接口内部的类
interface C{ class D{ public void fun(){ System.out.println("this is D class!"); } } D getDInstance(); } class E implements C{ @Override public D getDInstance() { return new D(); } }
正常情况下,不能再接口内部放置任何代码,但是嵌套类可以作为接口的一部分。你放到接口中的任何类都自动是public和static的。因为类是static的,只是将嵌套类至于接口的命名空间内,这并不违反接口的规则。你设置可以在内部类中实现外层接口。另外实现该接口的类,都可以使用该接口中的内部嵌套类,如上所示。
11.内部类的一个好处
要求,不使用内部类的情况下,实现下面的两个接口。
接口
interface A{ void fun(); } interface B{ int fun(); }
不使用内部类,实现两个接口
//The return type is incompatible with B.fun() class C implements A, B{ @Override public void fun() { } }
class C implements A{ @Override public void fun() { } } //The return types are incompatible for the inherited methods B.fun(), C.fun() class D extends C implements B{ }
使用内部类,方式1
class C implements A{ @Override public void fun() {} class D implements B{ @Override public int fun() { return 0; } } }
使用内部类,方式2
class C{ class D implements A{ @Override public void fun() { } } class E implements B{ @Override public int fun() { return 0; } } }
12.java不能使用范型数组原因
转自:http://www.cnblogs.com/exmyth/p/4598971.html
Java 不支持泛型数组。也就是说,
- List<String>[] ls = new ArrayList<String>[10];
是不支持的,而
- List<String>[] ls = new ArrayList[10] 或者 List[] ls = new ArrayList[10] 却可以。
是我一直不清楚为什么不能够声明泛型的数组,指定类型可以让编译的时候不会出现类型安全的提示。
直到今天我看到Sun的一篇文档才清楚,里面提到了一种情况:
- List<String>[] lsa = new List<String>[10]; // Not really allowed.
- Object o = lsa;
- Object[] oa = (Object[]) o;
- List<Integer> li = new ArrayList<Integer>();
- li.add(new Integer(3));
- oa[1] = li; // Unsound, but passes run time store check
- String s = lsa[1].get(0); // Run-time error: ClassCastException.
这种情况下,由于JVM泛型的擦除机制,在运行时JVM是不知道泛型信息的,所以可以给oa[1]赋上一个ArrayList<Integer>而不会出现ArrayStoreException,但是在取出数据的时候却要做一次类型转换,所以就会出现ClassCastException,如果可以进行泛型数组的声明,上面说的这种情况在编译期将不会出现任何的警告和错误,只有在运行时才会出错。而对泛型数组的声明进行限制,对于这样的情况,可以在编译期提示代码有类型安全问题,比没有任何提示要强很多。
基于以上的原因,Java不支持声明泛型数组,更确切地表达是:数组的类型不可以是类型变量,除非是采用通配符的方式,看下面这个例子:
- List<?>[] lsa = new List<?>[10]; // OK, array of unbounded wildcard type.
- Object o = lsa;
- Object[] oa = (Object[]) o;
- List<Integer> li = new ArrayList<Integer>();
- li.add(new Integer(3));
- oa[1] = li; // Correct.
- String s = (String) lsa[1].get(0); // Run time error, but cast is explicit.
因为对于通配符的方式,最后取出数据是要做显式的类型转换的,所以并不会存在上一个例子的问题。
13.try..catch..finally中的return
public static int fun(){ int x = 1; try{ return x; } catch(Exception e){ } finally { x = 2; } return x; } public static int fun(){ int x = 1; try{ return x; } catch(Exception e){ } finally { x = 2; return x; } } public static int fun(){ int x = 1; try{ if(x == 1) throw new Exception("test"); } catch(Exception e){ return x; } finally { x = 2; return x; } }
输出 1 2 1
14.内部类继承
class Outer{ private String s; public Outer(String s){ System.out.println("Outer initial :" + s); } public void outFun(){ System.out.println("outFun"); } class Inner{ public void innerFun(){ System.out.print("内部类调用外部类中的方法: "); outFun(); } } } class InheritInner extends Outer.Inner{ public InheritInner(Outer out){ out.super(); } @Override public void innerFun(){ super.innerFun(); System.out.println("InheritInner override innerFun"); } } public class Main{ public static void main(String[] args) { Outer out = new Outer("Outer"); InheritInner inheritInner = new InheritInner(out); inheritInner.innerFun(); } }
这是在《JAVA编程思想》上看到的一道例题,是关于继承inner classes(内隐类)的。 先把代码和书上的一些原话写出来,如下: 由于inner class的构造函数必须连接到一个reference指向outer class 对象身上,所以 当你继承inner class时,事情便稍微复杂些。问题出在“指向outer class对象”的那个 神秘reference必须被初始化。但derived class之内不存在可连接的缺省对象,这个问题 的答案是,使用专用语法,明确产生该关联性: class WithInner { class Inner{} } public class InheritInner extends WithInner.Inner { InheritInner(WithInner wi) { wi.super(); //---这里不懂,wi.super()指的是什么,有什么用? } public static void main(String[] args) { WithInner wi = new WithInner(); InheritInner ii = new InheritInner(wi); } }
15.java自定义注解类,如何获取注解,如何反射内部类,this$0是什么意思
本文来自博客园,作者:hjzqyx,转载请注明原文链接:https://www.cnblogs.com/hujunzheng/p/5638553.html