Java内部类
1.匿名内部类
内部类基础
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
分类:
成员内部类
局部内部类
匿名内部类
静态内部类
1.1 成员内部类
class Circle {
double radius = 0;
public Circle(double radius) {
this.radius = radius;
}
class Draw { //内部类
public void drawSahpe() {
System.out.println("drawshape");
System.out.println(radius); //外部类的private成员
System.out.println(count); //外部类的静态成员
}
}
}
注释
注释:
a)类Draw像是类Circle的一个成员,Circle称为外部类。成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)
==============================================
不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量
外部类.this.成员方法
==============================================
b)在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问:
class Circle {
private double radius = 0;
public Circle(double radius) {
this.radius = radius;
getDrawInstance().drawSahpe(); //必须先创建成员内部类的对象,再进行访问
}
private Draw getDrawInstance() {
return new Draw();
}
class Draw { //内部类
public void drawSahpe() {
System.out.println(radius); //外部类的private成员
}
}
}
c)成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。创建成员内部类对象的一般方式如下:
public class Test {
public static void main(String[] args) {
//第一种方式:
Outter outter = new Outter();
Outter.Inner inner = outter.new Inner();
//必须通过Outter对象来创建
//第二种方式:
Outter.Inner inner1 = outter.getInnerInstance();
}
}
class Outter {
private Inner inner = null;
public Outter() {
}
public Inner getInnerInstance() {
if(inner == null)
inner = new Inner();
return inner;
}
class Inner {
public Inner() {
}
}
}
d)内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。
2.2 局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内
class People{
public People() {
}
}
class Man{
public Man(){
}
public People getWoman(){
class Woman extends People{ //局部内部类
int age =0;
}
return new Woman();
}
}
注意,局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。
3.匿名内部类
4.静态内部类
静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
}
}
class Outter {
public Outter() {
}
static class Inner {
public Inner() {
}
}
}
2.内部类的使用场景和好处
1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整,
2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
3.方便编写事件驱动程序
4.方便编写线程代码
创建静态内部类对象的一般形式为: 外部类类名.内部类类名 xxx = new 外部类类名.内部类类名()
创建成员内部类对象的一般形式为: 外部类类名.内部类类名 xxx = 外部类对象名.new 内部类类名()
3. 注意事项
在使用匿名内部类的过程中,我们需要注意如下几点:
1、使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
2、匿名内部类中是不能定义构造函数的。
3、匿名内部类中不能存在任何的静态成员变量和静态方法。
4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
匿名内部类初始化
利用构造代码块能够达到为匿名内部类创建一个构造器的效果
反射技术
1.反射机制概念
主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,
调整或修改应用所描述行为的状态和相关的语义
2. 反射机制的作用
1)在运行时判断任意一个对象所属的类;
2)在运行时获取类的对象;
3)在运行时访问java对象的属性,方法,构造方法等。
3.反射机制的优点与缺点
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,
体现了多态的应用,有以降低类之间的藕合性。
反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性
反射机制的缺点:对性能有影响。
4.反射机制的示例
Class<T> bean;
Class<?> bean;
单独的T代表一个类型,而Class<T>和Class<?>代表这个类型所对应的类
Class<T>在实例化的时候,T要替换成具体类
Class<?>它是个通配泛型,?可以代表任何类型
<? extends T>受限统配,表示T的一个未知子类。
<? super T>下限统配,表示T的一个未知父类。
public T find(Class<T> clazz, int id);
5. 第一种使用forName(String * className)
/*
* 第一种使用forName(String * className),其中className一定是包含包的名字,下面的demo就是包的名字,Test是类的名字
*/
Class cls=Class.forName("demo.Test");
Test test=(Test)cls.newInstance();
//这里只是使用了默认的构造方法实例化对象
案例
共有构造方法
// 获取字节码
Class c = Class.forName("Person");
// 获取带参构造方法对象
Constructor con = c.getConstructor(String.class,int.class,String.class);
// 通过带参构造方法对象创建对象
Object obj = con.newInstance("aa",12,"bb");
System.out.println(obj);
私有构造方法
//获取字节码对象
Class c = Class.forName("Person");
// 获取私有构造方法
Constructor con = c.getDeclaredConstructor(String.class);
// 暴力访问
con.setAccessible(true);
//
Object obj = con.newInstance("aa");
System.out.println(obj);
通过发生获取成员变量并使用
//获取字节码对象
Class c = Class.forName("Person");
// 通过无参构造方法创建对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();
获取单个的成员变量
// 获取address并对其赋值
Filed addressField = c.getField("address");
// public void set(Object obj, Object Value);
// 将指定对象变量上此Field对象表示的字段设置为指定的新值
addressField.set(obj,"aa"); // 给obj对象的addressField字段设置值为”aa"
获取name并对其赋值
Field nameField = c.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj,"aa");
System.out.println(obj)
通过反射获取所有的方法
获取字节码对象
Class c = Class.forName("Person");
通过无参构造方法创建对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();
// public Method getMethod(String name, Class<?>..para)
// 第一个参数表示方法名 第二个参数表示方法的参数的class类型
Method m1 = c.getMethod("show");
// public Object invoke(Object obj, Object ...args)
// 返回值是Object接收,第一个参数表示对象是谁,第二个参数表示调用该方法的实际参数
m1.invoke(obj); // 调用obj的m1方法
Method m2 = c.getMethod("method", String.class);
m2.invoke(obj,"hello");
Method m3 = c.getMethod("getString", String.class,int.class);
// Object objString = m3.invoke(obj,"hello",100);
// System.out.println(objString);
String s= (String)m3.invoke(obj,"hello", 100);
私有方法
Method m4 = c.getDeclaredField("function");
m4.setAccessible(true);
m4.invoke(obj);
配置文件读取
Properties prop = new Properties();
FileReader fr = new FileReader("class.txt");
prop.load(fr);
fr.close();
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
Class c = class.forName(className);
Constructor con = c.getConstructor();
Object obj = con.newInstance();
Method m = c.getMethod(methodName);
m.invoke(obj);
ArrayList<Interger>的一个对象,在这个集合中添加一个字符串,如何实现
ArrayList<Interger> array = new ArrayList<Interger>();
Class c = array.getClass();
Method m = c.getMethod("add", Object.class);
m.invoke(array,"hello");
m.invoke(array,"world");
m.invoke(array,"java");
Tool类
Class Tool {
public void setProperty(Object obj,
String propertyName, Object value) {
Class c = obj.getClass();
Field filed = c.getDeclaredField(propertyName)
filed.setAccessible(true);
filed.set(obj,value);
}
}
动态代理
1)getConstructor(Class[] params)
获取公共的(public)的构造方法,并且限定其中的参数个数和类型可以获得不同的公共构造方法
2)Constructor[] getConstructors() 返回所有的公共(public)的构造方法
3)getDeclaredConstructor(Class[] params) 获取所有指定的构造方法,但是需要注意的是当获取私有的构造方法的时候
需要使用setAccessible设置访问权限为true才能进行构造,否则出现异常
4)Constructor[] getDeclaredConstructors()
返所有的构造方法包括public和private,protected修饰的
5)Method[] getMethods() 获取所有的公共的方法(public)返回的是一个数组(Method)
6)Method getDeclaredMethod(String name,Class<?>... parameterTypes)返回所有的指定的参数的方法(public,private,protected,
但是不包括继承的),其中参数可以为null(无参数)
7)Method[] getDeclaredMethods() 获取所有的方法
8)Field getField(String name) 指定名字的公共成员变量(public)
9)Field getDeclaredField(String name) 获取所有的指定名称的成员变量(public,protected,private),
同样在调用私有成员变量的时候需要先设置访问的权限,field.setAccessible(true)
NIO 和 BIO的区别
1.java NIO 和 阻塞I/O的区别
client read 阻塞
server accept 阻塞
缺点:1.客户端多时,创建大量的处理线程,占用栈空间和CPU时间
2.上下文切换浪费不必要的时间
2.java NIO原理及通信模型
1.原理
a)由一个专门的线程来处理所有的 IO 事件,并负责分发
b)事件驱动机制:事件到的时候触发,而不是同步的去监视事件
c)线程通讯:线程之间通过 wait,notify 等方式通讯。保证每次上下文切换都是有意义的。减少无谓的线程切换
3. server and Client 代码
4.一般selector使用的格式
while(true) {
selector.select() ;
Iterator it = selector.selectedKeys().iterator() ;
while( it.hasNext() ) {
SelectionKey key = it.next() ;
if( key.isReadable() )
… perform read() operation on key.channel() …
if( key.isWriteable() )
...
it.remove() ;
}
}
5.Buffer
基本操作:
buffer.limit() //取出limit位置
buffer.limit(int nl) //设置新limit位置
buffer.position() //得到pos
buffer.position(int) //设置新的pos
buffer.mark() //mark=pos,当前位置做标记
buffer.remaining() //lim-pos空间
buffer.hasRemaining() //lim-pos == 0?
JDBC
创建JDBC应用程序
1.导入包
在程序中包含数据库编程所需的JDBC类。
import java.sql.*;
2.注册JDBC驱动程序
需要初始化驱动程序,这样就可以打开与数据库的通信。
Class.forName("com.mysql.jdbc.Driver");
3.打开一个连接 使用DriverManager.getConnection()方法来创建一个Connection对象,它代表一个数据库的物理连接
static final String USER = "root";
static final String PASS = "pwd123456";
System.out.println("Connecting to database...");
conn = DriverManager.getConnection(DB_URL,USER,PASS);
4. 执行一个查询 需要使用一个类型为Statement或PreparedStatement的对象,并提交一个SQL语句到数据库执行查询
System.out.println("Creating statement...");
stmt = conn.createStatement();
String sql;
sql = "SELECT id, first, last, age FROM Employees";
ResultSet rs = stmt.executeQuery(sql);
如果要执行一个SQL语句:UPDATE,INSERT或DELETE语句,
那么需要下面的代码片段:
System.out.println("Creating statement...");
stmt = conn.createStatement();
String sql;
sql = "DELETE FROM Employees";
ResultSet rs = stmt.executeUpdate(sql);
5.从结果集中提取数据这一步中演示如何从数据库中获取查询结果的数据。
可以使用适当的ResultSet.getXXX()方法来检索的数据
结果如下://STEP 5: Extract data from result set
while(rs.next()){
//Retrieve by column name
int id = rs.getInt("id");
int age = rs.getInt("age");
String first = rs.getString("first");
String last = rs.getString("last");
//Display values
System.out.print("ID: " + id);
System.out.print(", Age: " + age);
System.out.print(", First: " + first);
System.out.println(", Last: " + last);
}
6.清理环境资源在使用JDBC与数据交互操作数据库中的数据后,应该明确地关闭所有的数据库资源以减少资源的浪费,对依赖于JVM的垃圾收集如下:
rs.close();
stmt.close();
conn.close();
Mysql数据配置信息
MySQL com.mysql.jdbc.Driver
jdbc:mysql://hostname/databaseName
JDBC Statements, PreparedStatement和CallableStatement语句接口
推荐使用
Statement
用于对数据库进行通用访问,在运行时使用静态SQL语句时很有用。Statement接口不能接受参数。
PreparedStatement
当计划要多次使用SQL语句时使用。PreparedStatement接口在运行时接受输入参数。
CallableStatement
当想要访问数据库存储过程时使用。CallableStatement接口也可以接受运行时输入参数。
JDBC事务
事务能够控制何时更改提交并应用于数据库。
它将单个SQL语句或一组SQL语句视为一个逻辑单元,如果任何语句失败,整个事务将失败。
1)关闭自动提交
-conn.setAutoCommit(false);
2)提交和回滚
conn.commit( );
conn.rollback( );
3)使用保存点
设置保存点(Savepoint)时,可以在事务中定义逻辑回滚点。 如果通过保存点(Savepoint)发生错误时,则可以使用回滚方法来撤消所有更改或仅保存保存点之后所做的更改。
try{
//Assume a valid connection object conn
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
//set a Savepoint
Savepoint savepoint1 = conn.setSavepoint("Savepoint1");
String SQL = "INSERT INTO Employees " +
"VALUES (106, 24, 'Curry', 'Stephen')";
stmt.executeUpdate(SQL);
//Submit a malformed SQL statement that breaks
String SQL = "INSERTED IN Employees " +
"VALUES (107, 32, 'Kobe', 'Bryant')";
stmt.executeUpdate(SQL);
// If there is no error, commit the changes.
conn.commit();
}catch(SQLException se){
// If there is any error.
conn.rollback(savepoint1);
}
JDBC批量处理
使用Statement对象进行批处理以下是使用Statement对象的批处理的典型步骤序列 -
1)使用createStatement()方法创建Statement对象。
2)使用setAutoCommit()将自动提交设置为false。
3)使用addBatch()方法在创建的Statement对象上添加SQL语句到批处理中。
4)在创建的Statement对象上使用executeBatch()方法执行所有SQL语句。
5)最后,使用commit()方法提交所有更改。
使用PrepareStatement对象进行批处理
以下是使用PrepareStatement对象进行批处理的典型步骤顺序 -
1)使用占位符创建SQL语句。
2)使用prepareStatement()方法创建PrepareStatement对象。
3)使用setAutoCommit()将自动提交设置为false。
4)使用addBatch()方法在创建的Statement对象上添加SQL语句到批处理中。
5)在创建的Statement对象上使用executeBatch()方法执行所有SQL语句。
6)最后,使用commit()方法提交所有更改。
// Create SQL statement
String SQL = "INSERT INTO Employees (id, first, last, age) " +
"VALUES(?, ?, ?, ?)";
// Create PrepareStatement object
PreparedStatemen pstmt = conn.prepareStatement(SQL);
//Set auto-commit to false
conn.setAutoCommit(false);
// Set the variables
pstmt.setInt( 1, 400 );
pstmt.setString( 2, "JDBC" );
pstmt.setString( 3, "Li" );
pstmt.setInt( 4, 33 );
// Add it to the batch
pstmt.addBatch();
// Set the variables
pstmt.setInt( 1, 401 );
pstmt.setString( 2, "CSharp" );
pstmt.setString( 3, "Liang" );
pstmt.setInt( 4, 31 );
// Add it to the batch
pstmt.addBatch();
//add more batches
.
.
.
.
//Create an int[] to hold returned values
int[] count = stmt.executeBatch();
//Explicitly commit statements to apply changes
conn.commit();
JDBC存储过程调用
创建CallableStatement对象
存在三种类型的参数:IN,OUT和INOUT
参数 描述
IN 创建SQL语句时其参数值是未知的。 使用setXXX()方法将值绑定到IN参数。
OUT 由SQL语句返回的参数值。可以使用getXXX()方法从OUT参数中检索值。
INOUT 提供输入和输出值的参数。使用setXXX()方法绑定变量并使用getXXX()方法检索值
msyql>-- 定义新的终止符,*****不要带空格*****
mysql>delimiter //
mysql>-- 创建存储过程
mysql>CREATE PROCEDURE simpleproc (OUT param1 INT)
BEGIN
SELECT COUNT(*) INTO param1 FROM users; -- into 是赋值方式之一
END
//
mysql>-- 查看存储过程的状态
mysql>show procedure status //
mysql>-- 查看指定存储过程创建语句
mysql>show create procedure simpleproc ;
mysql>-- 调用存储过程,@a在命令中定义变量
mysql>call simpleproc(@a)
存储过程的删除
DROP PROCEDURE [过程1[,过程2…]]