同步异步:
同步:多个请求同时执行,前面的未得到处理,那么后面的也不会得到处理,排队(数据没有读取完不能操作数据)
异步:多个请求同时执行,互不影响(边读取边操作数据)
阻塞非阻塞:
阻塞:
同一个代码中若是阻塞,后面的代码就不会执行,只要达到某个条件后执行后面的程序(客户端连接服务器端,一直等待连接)
非阻塞:
同一个代码中这个条件没有到执行条件,也不会影响后面程序的执行(客服端没有连接到服务器端也可以执行后面的代码)
使用通道实现高效读写(通道是双向的能读也能写):
//创建输入通道
FileChannel is=new FileInputStream("d:/io/a.txt").getChannel();
//创建输出通道
FileChannel os=new FileOutputStream("d:/io/b.txt").getChannel();
//调用方法实现传输
is.transferTo(0, is.size(), os);
os.close();
is.close();
创建ByteBuffer:
//创建大小为10204的buffer缓冲区
ByteBuffer buffer= ByteBuffer.allocate(1024);
使用ByteBuffer完成读写 方式一:
//用缓冲区实现复制
try {
FileInputStream is=new FileInputStream("d:/io/a.txt");
FileOutputStream os=new FileOutputStream("d:/io/d.txt");
//创建缓冲区大小为1024
ByteBuffer buffer=ByteBuffer.allocate(1024);
//获取通道
FileChannel ic = is.getChannel();
FileChannel oc = os.getChannel();
int len;
while ((len=ic.read(buffer))!=-1){
buffer.flip();
oc.write(buffer);
buffer.clear();
}
oc.close();
ic.close();
os.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
方式二:
//创建大小为10204的buffer缓冲区
ByteBuffer buffer= ByteBuffer.allocate(1024);
//创建输入通道
FileChannel is=new FileInputStream("d:/io/a.txt").getChannel();
//创建输出通道
FileChannel os=new FileOutputStream("d:/io/e.txt").getChannel();
int len;
while ((len=is.read(buffer))!=-1){
//实现读写转换 重设一下buffer:limit=position(之前position的位置) , 再将位置归零position=0
buffer.flip();
os.write(buffer);
buffer.clear();//重置buffer,重设position=0,limit=capacity,用于下次读取
}
os.close();
is.close();
反射:
//获取Student对象的字节码文件
//方式一 类名.class获取
// Class<Student> clazz = Student.class;
//方式二 对象名.getClass获取
// Student s=new Student();
// Class<? extends Student> clazz = s.getClass();
//方式三 Class的静态方法forName(全限定类名)
Class<?> clazz = Class.forName("com.itheima06.Student");
//反射获取类中无参构造方法
// Constructor<?> constructor = clazz.getConstructor();
//反射获取类中带参构造方法
Constructor<?> constructor = clazz.getDeclaredConstructor(int.class);//私有的
Constructor<?> constructor1 = clazz.getConstructor(String.class);
//私有的要进行暴力访问才能进行操作
constructor.setAccessible(true);
//根据构造方法创建对象
Object o = constructor.newInstance(18);
Student o1 = (Student) constructor1.newInstance("庞传钰");
//反射获取类中所有的公有构造方法
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor2 : constructors) {
System.out.println(constructor2);
}
//反射获取所有的构造方法
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
declaredConstructor.setAccessible(true);
System.out.println(declaredConstructor);
}
//反射获取类中的公有方法
Method method = clazz.getMethod("sport");
//执行方法
method.invoke(o);
//获取私有的方法
Method study = clazz.getDeclaredMethod("study",String.class);
//暴力访问
study.setAccessible(true);
study.invoke(o1,o1.getName());
//反射获取类中的公有变量
Field age = clazz.getField("age");
//赋值
age.set(o1,21);
System.out.println(age.get(o));
//反射获取类中私有变量
Field name = clazz.getDeclaredField("name");
//暴力访问
name.setAccessible(true);
name.set(o,"小明");
System.out.println(name.get(o));
public class Student {
private String name;
public int age;
public Student(String name) {
this.name = name;
}
private Student(int age) {
this.age = age;
}
public Student() {
}
private Student(String name, int age) {
this.name = name;
this.age = age;
}
private void study(String name){
System.out.println(name+"爱学习");
}
public void sport(){
System.out.println("爱运动");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
自定义注解:
注解属性支持的数据类型有:
* 八种数据数据类型(int,short,long,double,byte,char,boolean,float)
* String,Class,注解类型,枚举类
* 以上类型的一维数组形式
-
普通属性:
在使用注解的时候需要为注解的属性赋值!(定义注解属性给定的是什么类型的,那么使用的时候就给这个属性赋一个该类型的值) -
特殊属性value:
如果注解中只有一个属性且名字叫value,则在使用该注解时可以直接给该属性赋值,而不需要给出属性名。
如果注解中除了value属性之外还有其他属性且只要有一个属性没有默认值,则在给属性赋值时value属性名也不能省略了。 -
小结:如果注解中只有一个属性时,一般都会将该属性名命名为value
-
在使用自定义注解的时候要加上元注解
-
- @Target
作用:用来标识注解使用的位置,如果没有使用该注解标识,则自定义的注解可以使用在任意位置。
可使用的值定义在ElementType枚举类中,常量值如下
TYPE,类,接口
FIELD, 成员变量
METHOD, 成员方法
PARAMETER, 方法参数
CONSTRUCTOR, 构造方法
LOCAL_VARIABLE, 局部变量
…
- @Target
-
@Retention
作用:用来标识注解的生命周期(有效范围)
可使用的值定义在RetentionPolicy枚举类中,常用值如下
SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段
//元注解
//运行时
@Retention(RetentionPolicy.RUNTIME)
//可以定义在变量 方法和类上
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
//自定义注解
public @interface Book {
//书名
String name();
//价格默认值100
double price() default 100;
//作者
String writer();
}
//使用元注解
@Book(name = "斗罗大陆", writer = "唐家三少")
public class Student {
@Book(name = "斗破苍穹", writer = "天蚕土豆",price = 200)
String name;
@Book(name = "伏天氏", writer = "小明")
public void method(){
}
}
//获取字节码对象
Class<Student> clazz = Student.class;
//判断这个类上有没有使用Book的注解
if(clazz.isAnnotationPresent(Book.class)){
//获取注解对象
Book book = clazz.getAnnotation(Book.class);
//获取元素输出
System.out.println(book.name());
System.out.println(book.price());
System.out.println(book.writer());
}
//获取变量
Field name = clazz.getDeclaredField("name");
//判断这个变量上有没有使用Book的注解
if (name.isAnnotationPresent(Book.class)){
//获取注解对象
Book book = name.getAnnotation(Book.class);
System.out.println(book.name());
System.out.println(book.price());
System.out.println(book.writer());
}
//获取方法
Method method = clazz.getMethod("method");
//判断这个方法上有没有使用Book的注解
if(method.isAnnotationPresent(Book.class)){
//获取注解对象
Book book = method.getAnnotation(Book.class);
System.out.println(book.name());
System.out.println(book.price());
System.out.println(book.writer());
}
动态代理
动态代理可以对被代理对象的方法进行增强,可以在不修改方法源码的情况下,增强被代理对象方法的功能,在方法执行前后做任何你想做的事情。
//定义父接口动物
public interface Animal {
//定义方法吃
void eat();
}
//定义狗类实现动物接口
public class Dog implements Animal {
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
//定义猫类实现动物接口
public class Cat implements Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
//多态创建狗对象
Animal animal=new Dog();
//参数一是被代理对象字节码对象的类加载器,参数二是被代理对象字节码对象的所有父接口,参数三是代理类(使用匿名内部类)
Animal animal1 = (Animal) Proxy.newProxyInstance(animal.getClass().getClassLoader(), animal.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
* Object proxy: 被代理对象
* Method method:被代理对象的方法
* Object[] args:被代理对象的参数列表
* */
//增强方法
System.out.println("狗看家");
//获取这个对象的方法
method.invoke(animal, args);
return null;
}
});
animal1.eat();
Animal cat=new Cat();
Animal cat1 = (Animal) Proxy.newProxyInstance(cat.getClass().getClassLoader(), cat.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("猫抓老鼠");
method.invoke(cat, args);
return null;
}
});
cat1.eat();
- 动态代理非常的灵活,可以为任意的接口实现类对象做代理
- 动态代理可以为被代理对象的所有接口的所有方法做代理,动态代理可以在不改变方法源码的情况下,实现对方法功能的增强,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。 动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。
- 动态代理同时也提高了开发效率。
- 缺点:只能针对接口的实现类做代理对象,普通类是不能做代理对象的