java基础
基础补漏:
JVM模型:https://blog.csdn.net/qq_36704549/article/details/109390566
(1)jvm是一种用于计算设备的规范,它是一个虚构出来的机器,是通过在实际的计算机上仿真模拟各种功能实现的。
(2)jvm包含一套字节码指令集,一组寄存器,一个栈(存方法),一个垃圾回收堆(存对象和数组)和一个存储方法域(存类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等)。
(3)JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。
装箱与拆箱
装箱就是自动将基本数据类型转换成引用数据类型,拆箱就是自动将引用数据类型转换成基本数据类型
源码:
(一)Long,Short,Byte,Character:https://blog.csdn.net/dabusiGin/article/details/101161040
(二)Float,Doubler,Boolean:https://blog.csdn.net/dabusiGin/article/details/101205754
面向对象(提高代码的复用性,符合高内聚低耦合的思想,也更加安全):
面向对象是是把构成问题事务分解成各个对象,为了描叙某个事物在整个解决问题的步骤中的行为。
面向对象的编程语言,是将功能封装进对象,强调具备某些功能的对象,其实面向对象的语言是基于面向过程的,因为即使是调用某个对象,被调用的对象的方法也是通过面向过程的方式编写的。
面向对象三大特征与五大原则:
特征:封装,继承,多态
原则:
1.单一职责原则:(Single Responsibility Principle,SRP)
类之间的耦合,提高类的复用性(避免相同的职责分散到不同的类中)
2.接口隔离原则:(Interface Segregation Principle,ISP)
客户端程序不应该依赖它不需要的接口方法(功能)
3.开放封闭原则(Open-Close Principle,OCP)
模块的行为必须是开发的,支持扩展的(扩展不能影响太多已有程序模块)
4.里氏替换原则(Liskov Substitution Principle,Lsp)
子类型必须能够替换它们的父类,并出现在父类能够出现的如任何地方
5.依赖倒置原则(Dependence Inversion Priciple,DIP)
上层模块不应该依赖于下层模块,它们共同依赖于一个抽象(父类不能依赖子类,它们都要依赖到抽象类),抽象类不能依赖于具体,具体应该要依赖于抽象
集合体系:https://blog.csdn.net/qq_44769557/article/details/119522781
IO流(I/O 即输入Input/ 输出Output的缩写)
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
java中用“流(stream)”来抽象表示这么一个写入写出的功能,封装成一个“类”,都放在http://java.io这个包里面。
ArrayList的实现原理总结如下:
①数据存储是基于数组实现的,默认初始容量为10,数组元素的类型为Object类型,对ArrayList的所有操作底层都是基于数组的;
②添加数据时,首先需要检查元素个数是否超过数组容量,如果超过了则需要对数组进行扩容;插入数据时,需要将插入点k开始到数组末尾的数据全部向后移动一位。
③数组的扩容是新建一个大容量(原始数组大小+扩充容量)的数组,然后将原始数组数据拷贝到新数组,然后将新数组作为扩容之后的数组。数组扩容的操作代价很高,我们应该尽量减少这种操作。
④删除数据时,需要将删除点+1位置开始到数组末尾的数据全部向前移动一位。
⑤获取数据很快,根据数组下表可以直接获取。
使用:
import java.util.ArrayList; // 引入 ArrayList 类 ArrayList<E> objectName =new ArrayList<>(); // 初始化 E: 泛型数据类型,用于设置 objectName 的数据类型,只能为引用数据类型。 objectName: 对象名。 添加元素:对象名.add(); 获取元素:对象名.get(n); ---n元素索引值 修改元素:对象名.set(n,值) --- 第一个参数为索引位置,第二个为要修改的值 删除元素:对象名.remove(n)
Collections.sort(对象名); // 字母排序 计算大小:对象名.size() ---返回数组长度 排序:Collections.sort(对象名); ---字母排序(import java.util.Collections; // 引入 Collections 类) 其他方法:https://www.runoob.com/manual/jdk11api/java.base/java/util/ArrayList.html
LinkedList(双向链表):
学习文档:https://blog.csdn.net/u012068483/article/details/106709209
LinkedList的实现原理总结如下:
①数据存储是基于双向链表实现的。
②插入数据很快。先是在双向链表中找到要插入节点的位置index,找到之后,再插入一个新节点。 双向链表查找index位置的节点时,有一个加速动作:若index < 双向链表长度的1/2,则从前向后查找; 否则,从后向前查找。
③删除数据很快。先是在双向链表中找到要插入节点的位置index,找到之后,进行如下操作:node.previous.next = node.next;node.next.previous = node.previous;node = null 。查找节点过程和插入一样。
④获取数据很慢,需要从Head节点进行查找。
⑤遍历数据很慢,每次获取数据都需要从头开始。
使用:
// 引入 LinkedList 类 import java.util.LinkedList; LinkedList<E> list = new LinkedList<E>(); // 普通创建方法list 或者 LinkedList<E> list = new LinkedList(Collection<? extends E> c); // 使用集合创建链表 添加元素:list.add(值) 在列表开头添加元素:list.addFirst(值); 在列表结尾添加元素:list.addLast(值) 在列表开头移除元素:list.removeFirst() 在列表结尾移除元素:list.removeLast() 获取列表开头的元素:list.getFirst() 获取列表结尾的元素:list.getLast() 其他方法:https://www.runoob.com/manual/jdk11api/java.base/java/util/LinkedList.html
HashMap(链表+数组):
HashMap中有两个重要的参数:
初始容量大小和加载因子,初始容量大小是创建时给数组分配的容量大小,默认值为16,用数组容量大小乘以加载因子得到一个值,一旦数组中存储的元素个数超过该值就会调用rehash方法将数组容量增加到原来的两倍,专业术语叫做扩容.
在做扩容的时候会生成一个新的数组,原来的所有数据需要重新计算哈希码值重新分配到新的数组,所以扩容的操作非常消耗性能.
HashMap总结:
HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。
HashMap 实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步。
HashMap 是无序的,即不会记录插入的顺序。
HashMap 继承于AbstractMap,实现了 Map、Cloneable、java.io.Serializable 接口。
使用:
import java.util.HashMap; // 引入 HashMap 类 HashMap<Integer, String> Sites = new HashMap<Integer, String>(); //创建一个索引是Integer,值是String的HashMap对象 添加元素:对象名.put(n,值) ---n是索引 ---结果{n=值} 获取元素:Sites.get(n) 删除元素:Sites.remove(n) 删除所有元素:Sites.clear() 计算大小:Sites.size() 其他方法:https://www.runoob.com/manual/jdk11api/java.base/java/util/HashMap.html
HashSet:
HashSet的实现原理总结如下:
①是基于HashMap实现的,默认构造函数是构建一个初始容量为16,负载因子为0.75 的HashMap。封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。
②当我们试图把某个类的对象当成 HashMap的 key,或试图将这个类的对象放入 HashSet 中保存时,重写该类的equals(Object obj)方法和 hashCode() 方法很重要,而且这两个方法的返回值必须保持一致:当该类的两个的 hashCode() 返回值相同时,它们通过 equals() 方法比较也应该返回 true。通常来说,所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。
③HashSet的其他操作都是基于HashMap的。
hashSet特点:
HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。
HashSet 允许有 null 值。
HashSet 是无序的,即不会记录插入的顺序。
HashSet 不是线程安全的, 如果多个线程尝试同时修改 HashSet,则最终结果是不确定的。 您必须在多线程访问时显式同步对 HashSet 的并发访问。
HashSet 实现了 Set 接口。
使用:
import java.util.HashSet; // 引入 HashSet 类 HashSet<String> sites = new HashSet<String>(); //创建对象 添加元素:对像名.add(值) 判断元素是否存在:sites.contains(值) 删除元素:sites.remove(值) 删除所有元素:sites.clear() 计算大小:sites.size() 其他方法:https://www.runoob.com/manual/jdk11api/java.base/java/util/HashSet.html
maven:https://blog.csdn.net/u013142781/article/details/50316383
多线程:https://blog.csdn.net/qq_44715943/article/details/116714584
Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。
Reflection(反射)是java被视为动态语言的关键,反射机制允许程序在执行期借助Reflection API取得任何类的内部信息,并能直接操作任意内部属性及方法
加载完类之后,在堆内存的方法区就产生一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息,我们通过这个对象看到类的结构,这个对象就是一面镜子,透过这个镜子看到的类的结构成为:反射
编译期是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。
运行期是把编译后的文件交给计算机执行,直到程序运行结束。所谓运行期就把在磁盘中的代码放到内存中执行起来。
Java 反射机制主要提供了以下功能,这些功能都位于java.lang.reflect
包。
- 在运行时判断任意一个对象所属的类。
- 在运行时构造任意一个类的对象。
- 在运行时判断任意一个类所具有的成员变量和方法。
- 在运行时调用任意一个对象的方法。
- 生成动态代理。
优点:
- 能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
缺点:
- 反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
- 反射调用方法时可以忽略权限检查,获取这个类的私有方法和属性,因此可能会破坏类的封装性而导致安全问题。
获取class
//1、通过对象调用 getClass() 方法来获取,通常应用在:比如你传过来一个 Object 2 // 类型的对象,而我不知道你具体是什么类,用这种方法 3 Person p1 = new Person(); 4 Class c1 = p1.getClass(); 5 6 //2、直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高 7 // 这说明任何一个类都有一个隐含的静态成员变量 class 8 Class c2 = Person.class; 9 10 //3、通过 Class 对象的 forName() 静态方法来获取,用的最多, 11 // 但可能抛出 ClassNotFoundException 异常 12 Class c3 = Class.forName("com.ys.reflex.Person");
//4,通过类加载器xxxClassLoader.loadClass()
传入类路径获取:
ClassLoader.getSystemClassLoader().loadClass("cn.javaguide.TargetObject");
动态代理:
一个对象不能或不知何直接引用另一个对对象,而代理对象可以在客户端与对象之间其中介作用
组成:
执行步骤:
1.代理类
利用反射机制,在运行时创建代理类,接口和被代理类不变,构建ProxyInvocationHandler实现InvocationHandler接口
通过Proxy类静态方法newProxyInstance返回一个接口的代理实例,针对不同好的代理类,传入相应的代理程序控制器InvocationHandler
package com.guor.aop.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyInvocationHandler implements InvocationHandler { private Object target; public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } //生成得到代理类 public Object getProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this); } //处理代理实例,并返回结果 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { log(method.getName()); //动态代理的本质就是使用反射机制来实现 Object result = method.invoke(target, args); return result; } public void log(String msg) { System.out.println("执行了"+msg+"方法"); } }
2.被代理的类UserServiceImpl
package com.guor.aop; public interface UserService { public void add(); public void delete(); public void update(); public void query(); }
package com.guor.aop; public class UserServiceImpl implements UserService { public void add() { System.out.println("add"); } public void delete() { System.out.println("delete"); } public void update() { System.out.println("update"); } public void query() { System.out.println("query"); } }
3.执行动态代理
package com.guor.aop.dynamicproxy; import com.guor.aop.UserService; import com.guor.aop.UserServiceImpl; public class Client { public static void main(String[] args) { //真实角色 UserService userService = new UserServiceImpl(); //代理角色 ProxyInvocationHandler pih = new ProxyInvocationHandler(); //通过调用程序处理角色来处理我们要调用的接口对象 pih.setTarget(userService); UserService proxy = (UserService) pih.getProxy(); proxy.update(); } }
数据库操作
驱动---驱动jar---驱动类---连接字符串: Oracle---ojdbc-x.jar---oracle.jdbc.OraleDriver---jdbc:oracle:thin:2localhost:1521:ORCL MySQL---mysql-connector-java-x.jar ---com.mysql.jdbc.Driver---jdbc:mysql://localhost:3306/数据库实例名 SqlServer---sqljdbc-x.jar---com.microsoft.sqlserver.jdbc.SQLServerDriver---jdbc:microsoft:sqlserver:localhost:1433;databasename=数据库实例名 MYSQL: 1:注册驱动(三种) *a: class.forName("com.mysql.jdbc.Driver"); //不会对具体的驱动类产生依赖 b: DriverManager.registerDriver(com.mysql.jdbc.Driver); //会对具体的驱动类产生依赖 c: System.setProperty("jdbc.drivers","driver1:driver2"); //不会对具体的驱动类产生依赖,但注册不方便 2:建立连接 通过Connection建立连接,Connection是一个接口类,其功能是与数据库进行连接(会话)。 建立Connection接口类对象: *Connection conn =DriverManager.getConnection(url, user, password); //例:("jdbc:sqlserver://localhost:1433;DatabaseName=student", “sa", “123456") URL的格式要求为: JDBC:子协议:子名称//主机名:端口/数据库名?属性名=属性值&… 产生对象: 1.Statement---createStatement(); 2.PrepareStatement---PrepareStatement(); 3.CallableStatement---prepareCall(); 3:创建执行对象 执行对象Statement负责执行SQL语句,由Connection对象产生。 Statement接口类还派生出两个接口类PreparedStatement和CallableStatement,这两个接口类对象为我们提供了更加强大的数据访问功能。 创建Statement的语法为: *Statement st = conn.createStatement(); //bug: 用户名:任意值' or 1=1 -- 密码:任意值 { 关系:PreparedStatement继承自Statement,都是接口 区别:PreparedStatement可以使用占位符,是预编译的,批处理比Statement效率高 1、PreparedStatement:表示预编译的 SQL 语句的对象。 2、Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。 *PreparedStatement prst=conn.prepareStatement ("select * from stu where age>=? and sex=?")) //"?"表示in参数 格式: prst.setXXX(position,value) XXX指设置数据的各种类型,position-字段数/字段名 prst.setInt(1,20) //设置第一个参数值为20,整型 prst.setString(2,“男”) //设置第二 个参数值为男,字符型 } 4:执行SQL语句 执行对象Statement提供两个常用的方法来执行SQL语句。 executeQuery(Stringsql),该方法用于执行实现查询功能的sql语句,返回类型为ResultSet(结果集)。 executeUpdate(Stringsql),该方法用于执行实现增、删、改功能的sql语句,返回类型为int,即受影响的行数。 String sql=""; 5:处理执行结果(执行查询语句) ResultSet对象 ResultSet对象负责保存Statement执行后所产生的查询结果。 结果集ResultSet是通过游标来操作的。 next(): 游标就是一个可控制的、可以指向任意一条记录的指针。有了这个指针我们就能轻易地指出我们要对结果集中的哪一条记录进行修改、删除,或者要在哪一条记录之前插入数据。一个结果集对象中只包含一个游标。 previous():true/false getXxx(字段名|下标);获取字段值 6:释放资源 Connection对象的close方法用于关闭连接,并释放和连接相关的资源。 1.加载(注册)驱动程序(到JVM Class.forName(“com.microsoft.sqlserver.jdbc.SQLServerDrive”); 2.创建数据库连接 Connection conn=DriverManager.getConnection(url,user,pwd); 3.创建Statement对象 Statement stmt=conn.createStatement(); 4.创建Statement对象以后,可调用其中的方法执行SQL语句。 ResultSet rs=stmt.executeQuery(select * from stu); //values('"+name+"') //like '%"+name+"%' 假如结果集是rs (1) 得到元数据对象metaData ResultSetMetaData metaData = rs.getMetaData(); (2)得到结果集的列的个数,即共有几列 int columnCount = metaData.getColumnCount(); (3)结果集rs中的第i列的名字: String columnName = metaData.getColumnName(i); 对数据库的访问结束之后,及时地关闭相应对象,从而释放所占的资源 rs.close() //关闭ResultSet对象 stmt.close() //关闭Statement对象 con.close() //关闭Connection对象private static final] String URL="jdbc:oracle:thin:2localhost:1521:ORCL"; private static final] String user="root"; private static final] String pwd="123456"; pablic static] void update(){ Connection connection=null; Statement stmt=null; try{ class.forName("oracle.jdbc.OracleDriver"); connection=DriverManager.getConnection(URL,USERNAME,PWD); stmt=connection.createStatement(); String sql="insert into student value(1,'name')"; int count=stmt.executeUpdate(sql); if(count>0){ System.out.println("操作成功!"); }else{ System.out.println("操作失败!"); } }catch(ClassNotFoundException e){ e.printStackTrace(); }catch(SQLException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } finally{ try{ if(stmt =null) stmt.close(); if(connection!=null) connection.close(); }catch(SQLException e){ e.printStackTrace(); } } }