1、什么是多态?
多态,父类的引用指向子类的对象,使父类的引用呈现出子类的特性。好处在于减少了类之间的耦合性,例如:
public Abstract Class Car { void run(){...}; } public class BMW extends Car { //子类实现自己的run方法 void run(){...} } public Class MyCar { runCar(Car car) { car.run(); } }
通过父类的引用来调用子类的方法,如此可以免去为每种车定义不同的runCar方法,如runBMW(BMW bmw),从而是Car和MyCar两个类解耦。
2、抽象类与接口
1)从语法上,一个是abstract class,一个是interface,一个类可以实现多个接口,却只能继承一个抽象类,抽象类中可以有成员变量,方法可以有实现,但是接口中的变量只能是static finall的。
2)从含以上,抽象类与子类的关系是“is a”,而接口是“like a”,它赋予一个类更多的行为,是类属性与行为上更高层次上的抽象。如:给汽车赋予报警器的功能,这时候Car可以implements Alarm接口,并实现Alarm接口中的方法。
3、反射
反射是允许程序在运行时对自身进行检查(自审,Introspection),动态获取类的信息(类名,方法,成员变量,构造函数)和调用对象方法的特性。例如,
Class<?> clazz = Class.forName("java.lang.Object"); Object obj = clazz.newInstance(); Methdo method = clazz.getMethod("方法名",new Class[](int.Class,int.Class)); Object result = method.invoke();
应用举例——java动态代理
1)定义真实类的接口,及其实现
public interface MyAction { public void doAction(); }
public class Action1 implements MyAction{
public void doAction() { System.out.println("from Action1!!"); } }
2)定义代理类中,代理过程的实现
public class MyInvocationHandler implements InvocationHandler{ private Object obj; public MyInvocationHandler(Object obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before"+method); method.invoke(obj, args); System.out.println("after"+method); return null; } }
3)通过java的Proxy类动态生成代理类,返回一个真实类的接口,
public class ProxyTest { public static void main(String[] args) { Action1 action1 = new Action1(); MyInvocationHandler myInvocationHandler = new MyInvocationHandler(action1); MyAction action = (MyAction)Proxy.newProxyInstance(action1.getClass().getClassLoader(), action1.getClass().getInterfaces(),myInvocationHandler); action.doAction(); System.out.println(action.getClass()); } }
4、java内存模型
寄存器、栈(进程独享)、堆(共享)、静态区(方法去)、常量池(每个类都维护一个自己的常量池)。
堆区:
1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)
2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身
栈区:
1.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
方法区:
1.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
一个例子:
public class AppMain //运行时, jvm 把appmain的信息都放入方法区 { public static void main(String[] args) //main 方法本身放入方法区。 { Sample test1 = new Sample( " 测试1 " ); //test1是引用,所以放到栈区里, Sample是自定义对象应该放到堆里面 Sample test2 = new Sample( " 测试2 " ); test1.printName(); test2.printName(); } } Sample.java public class Sample //运行时, jvm 把appmain的信息都放入方法区 { /** 范例名称 */ private name; //new Sample实例后, name 引用放入栈区里, name 对象放入堆里 /** 构造方法 */ public Sample(String name) { this .name = name; } /** 输出 */ public void printName() //print方法本身放入 方法区里。 { System.out.println(name); } }
首先,系统收到了我们发出的指令,启动了一个Java虚拟机进程,这个进程首先从classpath中找到AppMain.class文件,读取这个文件中的二进制数据,然后把Appmain类的类信息存放到运行时数据区的方法区中。这一过程称为AppMain类的加载过程。
接着,Java虚拟机定位到方法区中AppMain类的Main()方法的字节码,开始执行它的指令。这个main()方法的第一条语句就是:
Sample test1=new Sample("测试1");
语句很简单啦,就是让java虚拟机创建一个Sample实例,并且呢,使引用变量test1引用这个实例。貌似小case一桩哦,就让我们来跟踪一下Java虚拟机,看看它究竟是怎么来执行这个任务的:
1、 Java虚拟机一看,不就是建立一个Sample实例吗,简单,于是就直奔方法区而去,先找到Sample类的类型信息再说。结果呢,嘿嘿,没找到@@,这会儿的方法区里还没有Sample类呢。可Java虚拟机也不是一根筋的笨蛋,于是,它发扬“自己动手,丰衣足食”的作风,立马加载了Sample类,把Sample类的类型信息存放在方法区里。
2、 好啦,资料找到了,下面就开始干活啦。Java虚拟机做的第一件事情就是在堆区中为一个新的Sample实例分配内存, 这个Sample实例持有着指向方法区的Sample类的类型信息的引用。这里所说的引用,实际上指的是Sample类的类型信息在方法区中的内存地址,其实,就是有点类似于C语言里的指针啦~~,而这个地址呢,就存放了在Sample实例的数据区里。
3、 在JAVA虚拟机进程中,每个线程都会拥有一个方法调用栈,用来跟踪线程运行中一系列的方法调用过程,栈中的每一个元素就被称为栈帧,每当线程调用一个方法的时候就会向方法栈压入一个新帧。这里的帧用来存储方法的参数、局部变量和运算过程中的临时数据。OK,原理讲完了,就让我们来继续我们的跟踪行动!位于“=”前的Test1是一个在main()方法中定义的变量,可见,它是一个局部变量,因此,它被会添加到了执行main()方法的主线程的JAVA方法调用栈中。而“=”将把这个test1变量指向堆区中的Sample实例,也就是说,它持有指向Sample实例的引用。
OK,到这里为止呢,JAVA虚拟机就完成了这个简单语句的执行任务。参考我们的行动向导图,我们终于初步摸清了JAVA虚拟机的一点点底细了,COOL!
接下来,JAVA虚拟机将继续执行后续指令,在堆区里继续创建另一个Sample实例,然后依次执行它们的printName()方法。当JAVA虚拟机执行test1.printName()方法时,JAVA虚拟机根据局部变量test1持有的引用,定位到堆区中的Sample实例,再根据Sample实例持有的引用,定位到方法去中Sample类的类型信息,从而获得printName()方法的字节码,接着执行printName()方法包含的指令。
5、类加载
将二进制Class文件加载到java内存中的方法区中。步骤
1)加载;
2)链接:验证;准备(为类的静态变量分配内存,并初始化为默认值);解析(将符号引用转化为直接引用)
3)初始化,为类的静态变量赋予正确的初始值。
注:只有当类或接口被首次主动使用时,才进行初始化步骤。
主动使用包括:
1)创建类实例;
2)方位某个类或接口的静态变量;
3)反射,Class.forName;
4)初始化一个类的子类;
5)被标明是启动类的类,包含main的类;
加载规则:父类委托
加载器类型:
1)根加载器(bootstrap),加载javahome/lib
2)扩展加载器,加载javahome/lib/ext
3)系统加载器,加载自定义类,是用户自定义类加载器的父类。
自定义ClassLoad——实现从自定义路径加载类
import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; public class MyClassLoader extends ClassLoader { private String name; private String path = "d:\\"; private final String fileType = ".class"; public MyClassLoader(String name) { super(); this.name = name; } public MyClassLoader(ClassLoader parent, String name) { super(parent); this.name = name; } @Override public String toString() { return this.name; } protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] data = loadClassData(name); return this.defineClass(name,data, 0, data.length); //throw new ClassNotFoundException(name); //return clazz; } private byte[] loadClassData(String name) { byte[] data = null; InputStream is = null; ByteArrayOutputStream bos = null; try { name = name.replace(".", "\\"); is = new FileInputStream(new File(path+name+fileType)); bos = new ByteArrayOutputStream(); int ch = 0; if(-1 != (ch= is.read())) { bos.write(ch); } data = bos.toByteArray(); } catch (Exception e) { e.printStackTrace(); } finally { try { bos.close(); is.close(); } catch(Exception e) { e.printStackTrace(); } } return data; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public String getFileType() { return fileType; } public static void main(String[] args)throws Exception { MyClassLoader loader1 = new MyClassLoader("loader1"); loader1.setPath("G:\\test\\server\\"); MyClassLoader loader2 = new MyClassLoader(loader1,"loader2"); loader2.setPath("G:\\test\\client\\"); MyClassLoader loader3 = new MyClassLoader(null, "loader3"); loader3.setPath("G:\\test\\other\\"); //test(loader1); //test(loader2); //test(loader3); Class clazz = loader1.loadClass("Sample"); Object obj = clazz.newInstance(); System.out.println(clazz.hashCode()); loader1 = null; clazz = null; obj = null; loader1 = new MyClassLoader("loader1"); loader1.setPath("G:\\test\\server\\"); clazz = loader1.loadClass("Sample"); obj = clazz.newInstance(); System.out.println(clazz.hashCode()); } public static void test(ClassLoader classLoader)throws Exception { Class clazz = classLoader.loadClass("Sample"); Object object = clazz.newInstance(); } }
6、jdbc和DAO
步骤:
1)加载驱动类
Class.forName("com.mysql.jdbc.Driver");
2)获取连接
Connection conn = DriverManager.getConnection("连接字","用户名","密码");
例子:
public class Test { public static void main(String[] args) { try { // 加载MySql的驱动类 Class<?> clazz = Class.forName("com.mysql.jdbc.Driver"); System.out.println(clazz.getClassLoader()); } catch (ClassNotFoundException e) { System.out.println("找不到驱动程序类 ,加载驱动失败!"); e.printStackTrace(); } String url = "jdbc:mysql://localhost:3306/test"; String username = "root"; String password = "123456"; try { String sql = "select * from custom"; String sql1 = "select * from custom where id = ?"; Connection conn = DriverManager.getConnection(url, username, password); PreparedStatement pstmt = conn.prepareStatement(sql1) ; pstmt.setInt(1, 1); /*Statement statement = conn.createStatement(); ResultSet rs = statement.executeQuery(sql);*/ ResultSet rs = pstmt.executeQuery(); while (rs.next()) { String name = rs.getString("name"); String pass = rs.getString(3); // 此方法比较高效 System.out.println(name + "**" + pass); } } catch (SQLException e) { e.printStackTrace(); } } }
使用PreparedStatement的好处:
1)有效的利用了数据库的缓存几只,DB会缓存部分重复使用的语句,如果是Statement的话,每次查询条件稍有不同就认为是不同语句,无法使用缓存
2)防止sql注入,如sql语句中有"select * from custom where id" = + username ,username是网页传来的值,那么username="yang or 1==1"就能使查询条件用为为真,从而查询到所有的信息。
DAO Factory
组件:
1)数值对象(VO)
public class CustomBean { }
2)DAO接口
public interface CustomDao { public List<CustomBean> findAll(); }
3)DAO接口实现类
public class CustomDaoImp implements CustomDao { @Override public List<CustomBean> findAll() { // TODO Auto-generated method stub return null; } }
public class CustomDaoImpHibernate implements CustomDao{...}
4)DAO工厂
public class DaoFactory { public static CustomDao getCustomDao() { return new CustomDaoImp(); //return new CustomDaoImpHibernate(); } }
优点:
1)实现了数据访问与业务逻辑的分离;
2)引入了Factory模式,通过工厂返回接口,隐藏了具体数据库操作的实现,与具体代码实现分离,可以是Hibernate或者jdbc,因此代码的修改只需修改DaoFactory中的返回的对象。
7、String、StringBuffer和StringBuilder
String不可变字符串,后两种通过append可以使字符串增长(要预留空间,所以初始化时要指定合适的长度,避免内存浪费)。
StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,只是StringBuffer 中的方法大都采用了 synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是线程不安全的。
StringBuffer 始于 JDK 1.0
StringBuilder 始于 JDK 1.5
从 JDK 1.5 开始,带有字符串变量的连接操作(+)如String s +="aa";,JVM 内部采用的是StringBuilder 来实现的,而之前这个操作是采用 StringBuffer 实现的。
发表评论
-
递归-组合(用背包问题解)
2011-04-01 21:23 748求指定数据的组合,这里的指定数据用一个数组模拟所有可以选择 ... -
Servlet和JSP的线程安全问题
2011-03-25 10:50 773不要定义servlet的类变量,不要使用jsp中的s ... -
Java同步机制浅谈―synchronized
2011-03-25 10:20 989Java对多线程的支持 ... -
代码复用的规则
2011-03-24 17:25 650李炜 北京杰合伟业软件公司产品技术部经理2001 年 7 ... -
java多进程——Java Multiple process (PID)
2011-03-24 10:48 1537Java的多进程运行模式分析 一般我们在java中运行其 ... -
用JSP实现假分页
2008-08-08 10:29 7361.使用MySql数据库建一个表,并添加记录: -- 删除表 ... -
用MVC模式实现真分页
2008-08-23 21:01 523·我们在之前代码上实现一个搜索框 输入查询关键字:< ... -
位运算符
2008-08-24 19:35 339Java 定义的位运算(bitwise operators ) ... -
struts高级技术——解决重复提交和上传文件
2008-08-24 19:44 433·解决重复提交的工具——Token令牌<?xml:nam ... -
从class.forName()说java中的reflection(反射/映像)
2008-09-21 21:19 530先通过我们一个熟悉的例子来说明: 使用JDBC时,我们都会很 ... -
eclipse 自动补全的设置,不用按 alt-/ 了
2011-03-23 11:07 701偶然间看到了这个,或许有和我一样不喜欢按 alt-/ 兄弟用得 ... -
用JSP实现假分页
2008-08-08 10:29 13441.使用MySql数据库建一个表,并添加记录: -- 删除表 ... -
用MVC模式实现真分页
2008-08-23 21:01 1154·我们在之前代码上实现一个搜索框 输入查询关键字:< ... -
位运算符
2008-08-24 19:35 750Java 定义的位运算(bitwise operators ) ... -
java排序大全
2008-08-24 19:42 648java排序大全 插入排序: packag ... -
struts高级技术——解决重复提交和上传文件
2008-08-24 19:44 840·解决重复提交的工具——Token令牌<?xml:nam ... -
从class.forName()说java中的reflection(反射/映像)
2008-09-21 21:19 904先通过我们一个熟悉的例子来说明: 使用JDBC时,我们都会很 ...
相关推荐
2.Java知识体系最强总结(含各个阶段的面试题) 3.Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java...
JavaOOP面试题 Java集合/泛型面试题 Java异常面试题 Java中的IO与NIO面试题 Java反射面试题 Java序列化面试题 Java注解面试题 多线程&并发面试题 JVM面试题 Mysql面试题 Redis面试题 Memcached面试题 MongoDB面试题 ...
java开发应聘必备,此文档可以让你之花2小时就可以基本掌握srping面试基础,总结了包括阿里,京东,字节跳动的大厂面试经历,基本看此文档就可以回顾sring和springmvc的基础知识了
│ java程序员面试资料.zip │ JAVA笔试题(上海释锐).pdf │ MIME简介.txt │ SCJP试题详解.pdf │ SQL面试题_心灵深处.htm │ Struts+Hibernate+Spring轻量级J2EE企业应用实战.pdf │ Struts中文手册.pdf │ ...
│ java程序员面试资料.zip │ JAVA笔试题(上海释锐).pdf │ MIME简介.txt │ SCJP试题详解.pdf │ SQL面试题_心灵深处.htm │ Struts+Hibernate+Spring轻量级J2EE企业应用实战.pdf │ Struts中文手册.pdf │ ...
│ java程序员面试资料.zip │ JAVA笔试题(上海释锐).pdf │ MIME简介.txt │ SCJP试题详解.pdf │ SQL面试题_心灵深处.htm │ Struts+Hibernate+Spring轻量级J2EE企业应用实战.pdf │ Struts中文手册.pdf │ ...
Java面试题(基础).pdf JVM 实用参数系列 - v1.0.pdf JVM与性能优化知识点整理.pdf JVM面试专题.docx JVM面试专题及答案.pdf Linux系统Redis笔记.docx MongoDB学习笔记.docx mybatis原理.docx MyBatis面试专题.docx...
│ java程序员面试资料.zip │ JAVA笔试题(上海释锐).pdf │ MIME简介.txt │ SCJP试题详解.pdf │ SQL面试题_心灵深处.htm │ Struts+Hibernate+Spring轻量级J2EE企业应用实战.pdf │ Struts中文手册.pdf │ ...
│ java程序员面试资料.zip │ JAVA笔试题(上海释锐).pdf │ MIME简介.txt │ SCJP试题详解.pdf │ SQL面试题_心灵深处.htm │ Struts+Hibernate+Spring轻量级J2EE企业应用实战.pdf │ Struts中文手册.pdf │ ...
太经典啦,JAVA编程题全集,包含大量题目最简洁最经典的解法,非常适合刷学完基础,刷题前的知识总结与开拓。里面包含大量题目以及50个直接执行的范例代码。java学习一点也不辛苦,需要的是好的资料。
能够快速实现高薪就业梦想,整合一些资料,以及相关的面试问题及面试技巧,希望在就业过程中,能够助力学子,少走一些弯路,通过面试宝典,能够进行针对向的复习和总结,在面试过程中,能够娴熟的运用所学知识和话术...
Java全栈相关的【知识技术解决方案难题面试题】知识库——内容涵盖(SpringBoot、SpringCloud相关的Java技术栈、常用中间件、数据结构与算法等基础课、项目遇到难题、面试题总结等)
基础知识系统总结: 重要知识点详解: (很重要的一个数据结构,用好枚举真的没有那么简单!) 其他: 容器 、 、 并发 面试题总结: 必备知识点: JVM 其他 I/O : Java 8 :、、 Java9~Java14 : Java编程规范: 、...
事务隔离性的一些基础知识 在组件之间实现事务和异步提交事务(NET2.0) 其它 在.NET访问MySql数据库时的几点经验! 自动代码生成器 关于能自定义格式的、支持多语言的、支持多数据库的代码生成器的想法 发布Oracle...
#前端开发面试题基础篇答案 来自网络和自己的总结 前端开发知识点: HTML&CSS: 对Web标准的理解、浏览器内核差异、兼容性、hack、CSS基本功:布局、盒子模型、选择器优先级、 HTML5、CSS3、Flexbox JavaScript...