java35-克隆-浅克隆-深克隆-java参数值传递-RMI-代理模式-静态代理-动态代理JDK-invocationHandler-newProxyInstance

本文主要是介绍java35-克隆-浅克隆-深克隆-java参数值传递-RMI-代理模式-静态代理-动态代理JDK-invocationHandler-newProxyInstance,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

时间
4/25

文章目录

      • 克隆
        • 概述
        • 实现克隆的方式
          • 实现Cloneable接口,并重写object类中的clone方法,可以实现浅克隆,也可以实现深克隆
          • 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的克隆
          • 利用BeanUtils,apache和spring都提供了bean工具,它是浅克隆
        • 浅克隆(Shallow Clone) 和 深克隆(Deep Clone)
          • 浅克隆(Shallow Clone)
          • 深克隆(Deep Clone)
        • 细节对比点
          • new操作符创建对象和clone方法复制对象的区别
          • 复制引用 和 复制对象 区别
          • 克隆两种实现方式的区别
      • java参数传递 = 值传递
      • RMI
      • Java中的动态代理
        • 代理模式
        • 静态代理
        • 动态代理
          • 基于接口的代理JDK
          • 基于继承的代理 CGlib

克隆

概述

克隆出现的原因:
在实际开发过程中,一个对象obj已经包含一些有用信息,这是我们需要将obj的信息复制到obj2中,使得obj和obj2对象具有两个完全不同的地址,修改一个对象的值,另一个对象不受影响。

实现克隆的方式
实现Cloneable接口,并重写object类中的clone方法,可以实现浅克隆,也可以实现深克隆
1 被克隆对象所属类必须实现Cloneable接口public class 类名 implements Cloneable{private 属性类 属性名;}
1-1 要想实现深克隆的话,类的成员属性 所在的类也需要实现Cloneable接口public class 属性类 implements Cloneable{}
2 所属类必须重写Object类的clone方法@Overridepublic Object clone() throws CloneNotSupportedException{类名 obj =(类名)super.clone(); // 浅克隆obj.属性名 = (属性类)属性名.clone(); //深克隆return obj;
}
实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的克隆
// 要序列化对象所属类 需要实现Serializable接口
public class 类名 implements Serializable{}
// 序列化
1 创建序列化流ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("文件路径"));
2 创建对象类名 obj = new 类名();
3 使用序列化流的writeObject方法将对象写入指定的ObjectOutputStream流中oos.writeObject(obj);
4 释放资源oos.close();// 反序列化
1 创建反序列化流ObjectInputStream ois = new ObjectInputStream(new FileInputStream("文件路径"));
2 使用反序列化流的readObject方法从ObjectInputStream流中读取一个对象Object obj = ois.readObject();
3 强制转化对象类型类型 obj1 = (类型)obj;
4 释放资源ois.close();
利用BeanUtils,apache和spring都提供了bean工具,它是浅克隆

扩展

  • BeanUtils 是工具类,用于简化JavaBean的封装,简化数据的封装。(xhj理解:和collections是一样的,同样是工具类)
  • apache 是 世界使用排名第一的Web服务器软件,具有跨平台和安全性的优势,是最流行的Web服务器端软件之一。
  • Spring框架是一个开放源代码的J2EE应用程序框架,针对bean的生命周期进行管理的轻量级容器。
    在Spring中,构成应用程序主干并由Spring IOC容器管理的对象称为bean。bean是一个由Spring IOC容器实例化、组装和管理的对象。
    实例的创建不再由调用者管理,而是由Spring容器创建,容器会负责控制程序之间的关系,而不是由程序代码直接控制。
浅克隆(Shallow Clone) 和 深克隆(Deep Clone)

两种克隆方式主要区别在于是否支持引用类型的成员变量的复制。
java中的数据类型分为:基本数据类型(数值型{整型、浮点型、字符型}) 和 引用数据类型(接口、类、数组)

浅克隆(Shallow Clone)

浅克隆中,对象的复制只是复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。
实现方法
覆盖Object类中的Clone()方法实现。

1 被复制的类需要实现Cloneable接口public class 类名 implements Cloneable{}
2 覆盖clone()方法,方法调用super.clone()方法得到需要的复制对象,输入clone有选项可以选择,自动生成。 修改为public访问级别@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}

实验分析:

1 被复制的类没有实现Cloneable接口,而直接使用  类名 对象2 = (类名)对象1.clone(); 会报错报clone()方法在java.lang.Object中是protected访问控制。
2 被复制的类实现Cloneable接口,使用 类名 对象2 = (类名)对象1.clone();  也会报错,需要抛出异常CloneNotSupportedException异常

案例:

// 320-test1
// 类
public class Student implements Cloneable{private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}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;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}// 测试类
public class StudentDemo {public static void main(String[] args) throws CloneNotSupportedException {Student s1 = new Student("汪苏泷",35);Student s2 = (Student)s1.clone();System.out.println(s1.getName() + ", " + s1.getAge());System.out.println("--------------");System.out.println(s2.getName() + ", " + s2.getAge());System.out.println(s1 == s2);// false 说明对象在堆内存中的地址不同}
}
深克隆(Deep Clone)

深克隆中,无论原型对象的成员变量的类型是值类型还是引用数据类型,都会复制一份给克隆对象。
实现方法:
方法一:通过覆盖Object类中的clone()方法实现

1 被复制对象的类 需要实现Cloneable接口,并重写Object类中的clone()方法。public class Outer implements Cloneable{private Inner inner;@Overridepublic Object clone() throws CloneNotSupportedException{Outer obj = (Outer)super.clone(); //类对象使用clone()方法obj.inner = (Inner)inner.clone();//类对象属性的类 使用clone()方法return obj;}}
2 Inner类也要实现Cloneable接口,重写Object类中的clone()方法。public class Inner implements Cloneable{@Overridepublic Object clone() throws CloneNotSupportedException{Inner obj = (Inner)super.clone();}
* 输入clone有选项可以选择 修改为public访问级别

方法二:使用序列化(Serialization)实现,序列化流ObjectOutputStream、反序列化流ObjectInputStream

// 序列化
1 创建序列化流对象ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("文件路径"));
2 创建对象类名 obj1 = new 类名();
3 使用序列化方法writeObject(Object obj)oos.writeObject(obj1);
4 释放资源oos.close();// 反序列化
1 创建反序列化对象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("文件路径"));
2 使用反序列化方法readObject()Object obj = ois.readObject();
3 强制类型转换 Object =》 类名类名 obj2 =(类名)obj;
4 释放资源ois.close();

方法一案例:

// 320-test2
// Student的属性 的类
public class Address implements Cloneable {private String address;public Address() {}public Address(String address) {this.address = address;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}
}// Student 要克隆的对象所属的类
public class Student implements Cloneable{private String name;private int age;private Address addr;// 创建的是Address类的对象public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}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;}public Address getAddr() {return addr;}public void setAddr(Address addr) {this.addr = addr;}@Overridepublic Object clone() throws CloneNotSupportedException {Student stu = (Student)super.clone();//浅克隆stu.addr = (Address)addr.clone();//深克隆return stu;}
}
// 测试类
public class StudentDemo {public static void main(String[] args) throws CloneNotSupportedException {Address addr = new Address("西安市");Student s1 = new Student("汪苏泷",35);s1.setAddr(addr);Student s2 = (Student)s1.clone();System.out.println(s1.getName() + ", " + s1.getAge()+", "+s1.getAddr().getAddress());System.out.println(s2.getName() + ", " + s2.getAge()+", " + s2.getAddr().getAddress());
//        System.out.println(s1 == s2);// false 说明对象在堆内存中的地址不同// 修改前输出:   汪苏泷, 35, 西安市//              汪苏泷, 35, 西安市// 两个对象的Addr变量都一样,为了验证原对象和新对象是两个不一样的,这里对s2对象的Addr变量修改值addr.setAddress("重庆市");System.out.println("修改之后");System.out.println("--------------");System.out.println(s1.getName() + ", " + s1.getAge()+", "+s1.getAddr().getAddress());System.out.println(s2.getName() + ", " + s2.getAge()+", " + s2.getAddr().getAddress());// 对s2对象的成员变量addr进行修改,s1对象的addr变量也发生了变化。//  =》 说明 没有实现深克隆,只完成了浅克隆,成员是值类型的复制。// 要想实现深克隆,需要给Student类中的addr变量所处在类Address设置为浅克隆实现。// Address实现cloneable、且重写clone方法// 修改前输出:汪苏泷, 35, 重庆市//           汪苏泷, 35, 重庆市// 修改后输出:汪苏泷, 35, 重庆市//           汪苏泷, 35, 西安市}
}
细节对比点
new操作符创建对象和clone方法复制对象的区别
具体操作newclone
分配内存根据new操作符后面的类型分配对应大小的内存空间分配与源对象相同大小的内存空间
填充对象的域调用构造方法,填充对象的各个域(对象的初始化)使用源对象中对应的各个域填充新对象的域
对象创建完毕构造方法返回创建完毕的对象,并将其引用地址发布到外部(栈内存)clone()方法返回对象,并将其引用发布到外部(栈内存)
复制引用 和 复制对象 区别

A 是 源对象,B 是 新对象
复制引用 = A 和 B 地址值 相同,说明是一个对象
复制对象 = A 和 B 地址值 不相同,说明是两个对象

克隆两种实现方式的区别
区别项实现Cloneable接口的方式序列化和反序列化方式
是否可以实现深度克隆可以,
若对象属性嵌套很多引用类型,则需要在类中写多个.clone()方法,使用不是很方便
可以,使用方便
是否支持编译时检测异常不支持,是在运行时抛出异常的支持,通过泛型限定,可以检查出克隆的对象是否支持序列化,在编译阶段完成

java参数传递 = 值传递

当java传递的参数是基本数据类型时,一个方法不能改变基本数据类型参数的值;
当java传递的参数是引用数据类型时,一个方法可以修改引用数据类型参数所指向的对象的值;
值传递的精髓:传递的是存储单元中的内容,而不是存储单元的引用。

基本数据类型参数

// idea_face-test2-TransferTest
public class TransferTest {public static void main(String[] args) {int num = 1;System.out.println("method()方法调用前=" + num);method(num);System.out.println("method()方法调用后=" + num);}public static void method(int number){number = 2;}//method()方法调用前=1//method()方法调用后=1
}

分析:
在这里插入图片描述
引用数据类型参数

public class TransterTest2 {public static void main(String[] args) {Person p = new Person("汪苏泷");System.out.println("调用方法前= name:" + p.getName());method(p);System.out.println("调用方法后= name:" + p.getName());}public static void method(Person p){p.setName("许嵩");}// 调用方法前= name:汪苏泷// 调用方法后= name:许嵩
}

分析:
在这里插入图片描述

RMI

  • RMI(Remote Method Invocation),远程方法调用,允许运行在一个java虚拟机的对象调用运行在另一个java虚拟机上的对象的方法。两个虚拟机可以是运行在相同计算机上的不同进程,也可以是运行在网络中的不同计算机。
  • RPC(Remote Procedure Call),远程过程调用,用于一个进程调用另一个进程。

Java中的动态代理

代理模式
  • 代理模式(Proxy或Surrogate),就是一个人或机构代替另一个人或机构采取行动。
    一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
    代理就是为其他对象提供一个代理以控制对某个对象的访问。
  • 优点:
    可以隐藏真实目标类的实现;可以实现客户与真实目标类之间的解耦,在不修改真实目标类代码的情况下能够做一些操作;
  • 代理模式实现条件:
    代理类和被代理类实现共同的接口(或继承);
    代理类中存在指向被代理类的索引;( xhj 这个代理类的索引 = 创建的真实类的对象 )
    实际执行是通过调用代理类的方法从而实际执行被代理类的方法。
  • 代理分类:
    静态代理:程序员创建或特定工具自动生成源码,在对其进行编译。运行前,代理类的.class文件就已经存在了;
    动态代理:程序运行时,运用反射机制动态创建而成,动态代理类的字节码文件在程序运行时由java反射机制动态生成,无需程序员手工编写它的源代码。
    • 动态代理分类:
      基于接口的代理:代表 = JDK代理
      基于继承的代理:代表 = CGlib代理
静态代理

实现步骤

1 创建一个接口MyInterface,并创建抽象方法public interface MyInterface{// 创建抽象方法public abstract 返回值类型 method(接口MyInterface参数);}
2 创建MyInterface真实的实现类RealClass,重写接口中的抽象方法public class RealClass implements MyInterface{// 重写接口中的抽象方法,此时方法不在带有abstract修饰符@Overridepublic 返回值类型 method(接口MyInterface参数){真实的实现过程;}}
3 创建 代理类public class ProxyClass implements MyInterface{// 创建接口MyInterface的实现类对象,// 这里创建的是接口MyInterface的真实类对象,也就是代理类中指向被代理类的索引private MyInterface myinterface;// 创建带参构造方法(真实类 真实类对象)ProxyClass(MyInterface myinterface){this.myinterface = myinterface;}// 重写接口MyInterface中的抽象类方法@Overridepublic method(接口MyInterface参数){调用代理方法前做的事情;返回值 x = myinterface.method(接口MyInterface参数);调用代理方法后做的事情;}

理解

  • 好处:
    比如每次从磁盘中获取字体库的时候,磁盘的I/O比较耗时,想通过缓存将读到的字体库暂存一份,直接修改代理类ProxyClass,不用修改真实RealClass类。
    同样这样的需求直接修改RealClass类也可以实现,但是当多个RealClass2,RealClass3也需要判断缓存是否有字体的时候,那么修改真实类就需要修改多个,而采用代理类的形式,只需要修改一个类即可。

代码
需求:考虑一个字体提供功能,字体库可能源自本地磁盘、网络或者系统。

// 326-test1
// 接口
// 先考虑从本地磁盘中获取字体,采用代理的方式实现,定义一个提供字体的接口FontProvider:
public interface FontProvider {Font getFont(String name);
}
// 真实类:真正提供获取磁盘字体库的类
public class FontProviderFromDisk implements FontProvider{@Overridepublic Font getFont(String name) {System.out.println("磁盘上的字体库");return null;}// 只是输出文字,返回值类型可以不写为Font类型,而是写为void
}
// 代理类
public class ProxyForFont implements FontProvider{private FontProvider fontProvider;// 定义一个接口对象,实际上是被代理类对象ProxyForFont(FontProvider fontProvider){this.fontProvider = fontProvider;}// 定义带参构造方法,参数为接口对象@Overridepublic Font getFont(String name) {System.out.println("提供代理方法前做的事情");Font font = fontProvider.getFont(name);System.out.println("调用代理后做的事情");return font;}
}
// 测试类
public class MyFontDemo {public static void main(String[] args) {FontProvider fp = new ProxyForFont(new FontProviderFromDisk());// 多态的形式创建FontProvider接口对象// 接口 对象名 = new 代理类名(new 真实类名());fp.getFont("宋体");}
}
动态代理

出现的原因
当需要获取多种资源,比如字体、图片、音乐等资源,这时就需要多个接口,比如FontProvider、ImageProvider、MusicProvider接口等,需要对应的实现类(比如FontClass、ImageClass、MusicClass等),和其对一个的代理类(比如FontProxy、ImageProxy、MusicProxy等)。当需要给获取字体、图片、音乐等功能上加上缓存功能,就需要对三个代理类进行改动,但是修改的部分逻辑上又相同,就会造成代码的重复和代理类爆炸。
分类: 基于接口的代理(JDK) 和 基于继承的代理(CGlib)

基于接口的代理JDK

InvocationHandler接口

  • InvocationHandler接口
    每个代理类的实例都会有一个与之相关联的InvocationHandler实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。
public interface InvocationHandler { // 接口// 唯一的方法invokepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}

参数介绍:

参数名说明
Object proxy代理对象
Method method代理对象调用的方法
Object[] args调用方法中的参数

Proxy类的静态newProxyInstance方法
返回指定接口的代理实例,该代理实例将方法调用分配给指定的调用处理程序。

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

参数介绍:

参数名说明获得
ClassLoader loader类加载器测试类.class.getClassLoader()
Class<?>[] interfaces用来代理的接口new Class[]{接口.class}
也就是说这里可以是多个接口.class
InvocationHandler h一个InvocationHandler对象InvocationHandler handler = new jdkProxyClass(new RealSubject());
jdkProxyClass是代理类,RealSubject是真实类

说明

  • 测试类.class.getClassLoader()
    测试类.class,得到该类对应的Class类对象,通过类的class属性
    Class类对象.getClassLoader(),得到Class类对象的类加载器
  • Class<?>[] interfaces = new Class[]{接口.class}
    2022/4/25 理解:需要创建一个Class数组,成员是接口的Class对象。

具体的实现步骤

1 创建接口MyInterfacepublic interface MyInterface{// 定义抽象方法public abstract 返回值类型 method1();public abstract 返回值类型 method2();}2 创建真实的接口实现类RealClasspublic class RealClass{// 重写抽象方法@Overridepublic 返回值类型 method1(){method1具体的实现;}@Overridepublic 返回值类型 method2(){method2具体的实现;}}3 创建接口的代理类,需要实现InvocationHandler接口public class jdkProxyClass implements InvocationHandler{// 创建接口的真实类对象private RealClass realObj;// 创建真实类对象为参数的带参构造方法public jdkProxyClass(RealClass realObj){this.realObj = realObj;}// 重写Object类中的invoke方法public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// proxy 被代理的对象;method:调用的方法;args:方法所需的参数执行代理调用之前的操作。Object result = null;// 这里的方法是通过反射获取的方法对象result = method.invoke(realObj,args);return result;}4 创建测试类public class jdkDemo{public static void main(String[] args){// 创建要代理的真实对象,采用多态的形式MyInterface realObj = new RealClass();// 创建代理对象InvocationHandler handler = new jdkProxyClass(realObj);// 使用Proxy.newProxyInstrace()这个静态方法 获得接口的对象MyInterface myinterface = (MyInterface)Proxy.newProxyInstance(jdkDemo.class.getClassLoader(),new Class[]{MyInterface.class},handler);// 通过接口对象调用方法myinterface.method1();myinterface.method2();}

案例:

// 326-test2
// 接口定义
public interface Subject {void method1();void method2();
}
// 接口真实的实现类定义
public class RealSubject implements Subject{@Overridepublic void method1() {System.out.println("method1执行");}@Overridepublic void method2() {System.out.println("method2执行");}
}// 接口的代理类定义
public class jdkProxySubject implements InvocationHandler {// 创建代理类的真实对象,也就是真实类的对象private Object subject;// 创建带参构造方法public jdkProxySubject(Object subject){this.subject = subject;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// proxy:被代理的对象// method:调用的方法// args:方法所需要的参数System.out.println("before");Object result = null;try{// 利用反射动态的来反射方法,动态代理和静态代理的区别result = method.invoke(subject, args);}catch(Exception e){System.out.println("ex:" + e.getMessage());}finally {System.out.println("after");}return result;}
}
// 测试类
public class Client {public static void main(String[] args){// 创建要代理的真实对象Subject realSubject = new RealSubject();// 创建代理对象,将真实对象作为参数传入InvocationHandler handler =new jdkProxySubject(realSubject);Subject subject = (Subject)Proxy.newProxyInstance(Client.class.getClassLoader(), new Class[]{Subject.class}, handler);subject.method1();subject.method2();}
}
基于继承的代理 CGlib

概述

  • CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,为一个类创建子类,并在子类中采用方法拦截技术 拦截所有对父类方法的调用,并顺势加入横切逻辑。
    ASM是一款java字节码层面的代码分析和修改工具。
    ASM的目标是生成、转换、分析已编译的java class文件,可使用ASM工具读/写/转换JVM指令集。
  • CGlib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理,因为采用的是继承,所以不能对final修饰的类进行代理。
    由于spring框架中的MethodInterceptor接口,目前没有学习spring框架 ,后期总结。
    参考博客

这篇关于java35-克隆-浅克隆-深克隆-java参数值传递-RMI-代理模式-静态代理-动态代理JDK-invocationHandler-newProxyInstance的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/693468

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

高效+灵活,万博智云全球发布AWS无代理跨云容灾方案!

摘要 近日,万博智云推出了基于AWS的无代理跨云容灾解决方案,并与拉丁美洲,中东,亚洲的合作伙伴面向全球开展了联合发布。这一方案以AWS应用环境为基础,将HyperBDR平台的高效、灵活和成本效益优势与无代理功能相结合,为全球企业带来实现了更便捷、经济的数据保护。 一、全球联合发布 9月2日,万博智云CEO Michael Wong在线上平台发布AWS无代理跨云容灾解决方案的阐述视频,介绍了