首页
苏兮影视
随笔记
壁纸
更多
直播
时光轴
友联
关于
统计
Search
1
软件添加id功能按钮
760 阅读
2
v2ray节点搭建
731 阅读
3
typecho非常有特色的模块
549 阅读
4
QQxml消息卡片生成源码
503 阅读
5
网易云音乐歌单ID获取教程
476 阅读
谈天说地
建站源码
经验教程
资源分享
动漫美图
登录
Search
标签搜索
java
flutter
springboot
rust
安卓
linux
vue
docker
joe
快捷键
git
fish shell
maven
redis
netty
dart
groovy
js
设计模式
rpc
尽意
累计撰写
103
篇文章
累计收到
39
条评论
首页
栏目
谈天说地
建站源码
经验教程
资源分享
动漫美图
页面
苏兮影视
随笔记
壁纸
直播
时光轴
友联
关于
统计
搜索到
103
篇与
的结果
java浅拷贝深拷贝
在Java中,深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是两个常见的对象拷贝方式。它们的主要区别在于它们处理对象中的引用类型字段的方式。1. 浅拷贝(Shallow Copy)浅拷贝仅拷贝对象本身以及对象中所有的基本数据类型字段,对于引用类型字段(如对象、数组等),仅复制其引用(即指针),而不复制实际的对象。这意味着原对象和拷贝对象中的引用类型字段指向同一个内存地址,因此改变一个对象中的引用类型字段可能会影响到另一个对象。实现方式:实现Cloneable接口并重写clone()方法。代码示例:class Address { String city; public Address(String city) { this.city = city; } } class Person implements Cloneable { String name; Address address; public Person(String name, Address address) { this.name = name; this.address = address; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); // 浅拷贝 } } public class ShallowCopyExample { public static void main(String[] args) throws CloneNotSupportedException { Address address = new Address("New York"); Person person1 = new Person("John", address); Person person2 (Person) person1.clone(); System.out.println(person1.address.city); // New York System.out.println(person2.address.city); // New York person2.address.city = "San Francisco"; System.out.println(person1.address.city); // San Francisco System.out.println(person2.address.city); // San Francisco } }应用场景:浅拷贝适用于对象结构简单且不包含复杂的嵌套对象的情况。因为浅拷贝的速度较快,适合对性能有较高要求但不涉及深层嵌套结构的场景。2. 深拷贝(Deep Copy)深拷贝不仅拷贝对象本身,还会递归地拷贝对象中所有引用类型字段所指向的对象。这意味着原对象和拷贝对象中的引用类型字段互不影响,修改一个对象中的引用类型字段不会影响到另一个对象。实现方式:重写clone()方法,手动拷贝所有的引用类型字段。使用序列化和反序列化实现深拷贝。代码示例:class Address implements Cloneable { String city; public Address(String city) { this.city = city; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable { String name; Address address; public Person(String name, Address address) { this.name = name; this.address = address; } @Override protected Object clone() throws CloneNotSupportedException { Person clonedPerson = (Person) super.clone(); clonedPerson.address = (Address) address.clone(); // 深拷贝 return clonedPerson; } } public class DeepCopyExample { public static void main(String[] args) throws CloneNotSupportedException { Address address = new Address("New York"); Person person1 = new Person("John", address); Person person2 = (Person) person1.clone(); System.out.println(person1.address.city); // New York System.out.println(person2.address.city); // New York person2.address.city = "San Francisco"; System.out.println(person1.address.city); // New York System.out.println(person2.address.city); // San Francisco } }应用场景:深拷贝适用于对象结构复杂且包含多个嵌套引用类型字段的场景,尤其是在这些引用类型字段是可变对象时。深拷贝确保拷贝后的对象与原对象完全独立,不会互相影响。总结浅拷贝:仅复制对象及其基本数据类型字段,引用类型字段只复制引用。适用于简单的对象结构。深拷贝:复制对象及其所有引用类型字段所指向的对象。适用于复杂对象结构,确保深层次的独立性。根据具体需求选择合适的拷贝方式可以有效地避免不必要的副作用并提高程序的性能。
2024年08月25日
68 阅读
0 评论
1 点赞
Java动态代理rpc
Java 动态代理在远程过程调用(RPC)中非常有用,可以隐藏网络通信的复杂性,使得远程调用看起来像是本地方法调用。场景说明假设我们有一个简单的服务接口 CalculatorService,它提供了加法和减法的功能。我们希望客户端可以通过动态代理的方式调用这个服务接口,实际上这些调用会通过网络发送到远程的服务端进行计算。1. 定义服务接口首先定义一个服务接口 CalculatorService:// 服务接口 public interface CalculatorService { int add(int a, int b); int subtract(int a, int b); }2. 实现服务端服务端实现了 CalculatorService 接口,并在远程提供服务:import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.ServerSocket; import java.net.Socket; // 服务端实现类 public class CalculatorServiceImpl implements CalculatorService { @Override public int add(int a, int b) { return a + b; } @Override public int subtract(int a, int b) { return a - b; } public static void main(String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket(8080); System.out.println("服务端启动,等待连接..."); while (true) { Socket clientSocket = serverSocket.accept(); ObjectInputStream input = new ObjectInputStream(clientSocket.getInputStream()); String methodName = input.readUTF(); int a = input.readInt(); int b = input.readInt(); ObjectOutputStream output = new ObjectOutputStream(clientSocket.getOutputStream()); CalculatorService service = new CalculatorServiceImpl(); if (methodName.equals("add")) { output.writeInt(service.add(a, b)); } else if (methodName.equals("subtract")) { output.writeInt(service.subtract(a, b)); } output.flush(); clientSocket.close(); } } }3. 实现客户端动态代理客户端使用动态代理调用远程服务:import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.Socket; // 动态代理处理器 public class RpcInvocationHandler implements InvocationHandler { private String host; private int port; public RpcInvocationHandler(String host, int port) { this.host = host; this.port = port; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Socket socket = new Socket(host, port); ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); output.writeUTF(method.getName()); for (Object arg : args) { output.writeObject(arg); } ObjectInputStream input = new ObjectInputStream(socket.getInputStream()); Object result = input.readObject(); input.close(); output.close(); socket.close(); return result; } } // 客户端代码 public class RpcClient { @SuppressWarnings("unchecked") public static <T> T getProxy(Class<T> serviceClass, String host, int port) { return (T) Proxy.newProxyInstance(serviceClass.getClassLoader(), new Class<?>[]{serviceClass}, new RpcInvocationHandler(host, port)); } public static void main(String[] args) { CalculatorService service = RpcClient.getProxy(CalculatorService.class, "localhost", 8080); int result1 = service.add(10, 5); int result2 = service.subtract(10, 5); System.out.println("加法结果: " + result1); System.out.println("减法结果: " + result2); } }4. 运行说明服务端:运行 CalculatorServiceImpl,它将开启一个 TCP 服务器,在 8080 端口等待客户端请求。客户端:运行 RpcClient,通过动态代理获得 CalculatorService 的代理对象,并调用 add 和 subtract 方法。这些方法调用将通过网络发送到服务端,由服务端处理并返回结果。5. 执行结果运行客户端后,输出如下:加法结果: 15 减法结果: 56. 解析服务端:简单实现了一个 TCP 服务器,通过 ObjectInputStream 和 ObjectOutputStream 来接收和发送请求。客户端:使用 JDK 动态代理,通过 RpcInvocationHandler 拦截方法调用,将方法名和参数序列化后发送给服务端,再从服务端获取结果。
2024年08月23日
81 阅读
0 评论
1 点赞
代理模式
代理模式(Proxy Pattern)是设计模式中的一种结构型模式。它为其他对象提供一种代理以控制对这个对象的访问。在 Java 中,代理模式有多种实现方式,主要分为静态代理和动态代理。1. 代理模式的基本概念意图:代理模式通过创建一个代理对象来代替实际对象,并且可以控制对实际对象的访问。代理对象和实际对象通常实现相同的接口或继承相同的类。结构:Subject(抽象主题接口/类):定义了真实对象和代理对象的公共接口或父类。RealSubject(真实主题类):实现了抽象主题接口,是代理对象所代表的真实对象。Proxy(代理类):持有一个对真实对象的引用,实现了抽象主题接口,并在调用时对真实对象进行操作。适用场景:需要对原对象的功能进行扩展或控制,而不改变原对象的代码。需要对某个类的访问进行控制,比如延迟加载、安全代理、远程代理等。2. 静态代理特点:预先定义:代理类在编译时就已经创建好了,代理类和真实类需要实现相同的接口。代理行为固定:代理类的行为是静态的,不能在运行时改变。优缺点:优点:实现简单,容易理解,能够在编译时进行类型检查。缺点:代理类与真实类高度耦合,代理类过多会导致代码冗余,不适合扩展性需求高的场景。示例代码:// 定义接口 public interface Subject { void request(); } // 真实主题类 public class RealSubject implements Subject { @Override public void request() { System.out.println("真实主题处理请求"); } } // 代理类 public class Proxy implements Subject { private RealSubject realSubject; public Proxy(RealSubject realSubject) { this.realSubject = realSubject; } @Override public void request() { System.out.println("代理开始处理"); realSubject.request(); System.out.println("代理完成处理"); } } // 测试代码 public class Main { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); Proxy proxy = new Proxy(realSubject); proxy.request(); } }3. 动态代理特点:动态生成:动态代理类在运行时由 JVM 动态生成,不需要事先定义代理类。灵活性高:可以在运行时灵活地决定代理行为。实现方式:JDK 动态代理:基于反射机制,只能代理实现了接口的类。CGLIB 动态代理:基于字节码生成,可以代理没有实现接口的类,常用于 Spring 框架。优缺点:优点:减少了静态代理的冗余代码,增强了扩展性,可以动态地为多个对象创建代理。缺点:性能略低于静态代理,调试较为复杂,尤其是对生成的动态代理类进行调试。JDK 动态代理示例代码:import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // 定义接口 public interface Subject { void request(); } // 真实主题类 public class RealSubject implements Subject { @Override public void request() { System.out.println("真实主题处理请求"); } } // 动态代理处理器 public class DynamicProxyHandler implements InvocationHandler { private Object target; public DynamicProxyHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理开始处理"); Object result = method.invoke(target, args); // 调用真实对象的方法 System.out.println("代理完成处理"); return result; } } // 测试代码 public class Main { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); Subject proxyInstance = (Subject) Proxy.newProxyInstance( realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), new DynamicProxyHandler(realSubject) ); proxyInstance.request(); } }4. 代理模式的常见应用安全代理:控制对原始对象的访问,确保安全性。延迟加载:在需要时才创建或加载实际对象,以提高性能。远程代理:为远程对象提供本地代理,使远程调用看起来像本地调用。虚拟代理:控制对象的访问以延迟实际对象的创建和初始化。保护代理:通过代理来控制对象的访问权限。5. 总结代理模式是一种非常有用的设计模式,它通过引入代理对象来控制对实际对象的访问。静态代理适合简单和固定的场景,而动态代理则提供了更强的灵活性和扩展性。理解代理模式的使用场景和实现方式,可以帮助开发者编写更灵活、更易维护的代码。
2024年08月21日
74 阅读
0 评论
4 点赞
2024-08-16
idea插件开发
插件商店下载插件 Plugin Devkit新建项目 选择IDE插件jdk版本跟ida参考https://plugins.jetbrains.com/docs/intellij/creating-plugin-project.html#creating-a-plugin-with-new-project-wizard2024.2+ 版本需要使用java212022.2 - 2024.2 版本需要使用java17 支持创建项目完成之后,先停止gradle的构建修改几个文件将build.gradle.kts setting.gradle.kts 的后缀名.kts去掉kotlin目录修改为java修改后的目录修改plugin.xml配置文件,可用看到这些爆红的地方都是要修改的,不修改也不影响运行,还是改一下好了修改build.gradle文件plugins { id 'java' id 'org.jetbrains.kotlin.jvm' version '1.9.23' id 'org.jetbrains.intellij' version '1.17.3' } group = 'com.suxii' version = '1.0.0' repositories { mavenCentral() } intellij { // 改为本地路径 localPath = 'D:\\Program Files\\JetBrains\\IntelliJ IDEA 2024.1.2' plugins = [/* Plugin Dependencies */] } tasks.withType(JavaCompile).configureEach { sourceCompatibility = '17' targetCompatibility = '17' options.encoding = "UTF-8" } tasks.patchPluginXml { sinceBuild = '232' untilBuild = '242.*' } tasks.signPlugin { certificateChain = System.getenv('CERTIFICATE_CHAIN') privateKey = System.getenv('PRIVATE_KEY') password = System.getenv('PRIVATE_KEY_PASSWORD') } tasks.publishPlugin { token = System.getenv('PUBLISH_TOKEN') } 修改完成后点击图标重新同步一下右键新建-》选择Swing UI设计器-》GUI窗体输入窗体名字可用看到自动生成了.form文件点这个.form文件就可用进行可视化布局补充一下相关布局模式的简单说明布局模式的简单说明: BorderLayout(边框布局): 描述:这是一个经典的布局管理器,将组件分布在五个区域:北(North)、南(South)、东(East)、西(West)和中(Center)。 使用场景:适用于创建结构良好的界面,主要内容位于中央,次要组件(如工具栏或状态栏)位于边缘。 FlowLayout(流式布局): 描述:组件依次水平或垂直排列,空间不足时会自动换行。 使用场景:适合简单表单或工具栏的布局,组件应该自然流动。 GridLayout(网格布局): 描述:将容器分成均匀的网格,每个组件占据一个网格单元。 使用场景:适用于需要将多个组件整齐排列成行列的场景,例如表格或控制面板。 GridBagLayout(网格包布局): 描述:类似于网格布局,但每个组件可以跨越多个网格单元,且可以对齐、填充和加权。 使用场景:适合复杂的用户界面,组件大小不一致且需要精确定位。 CardLayout(卡片布局): 描述:允许在同一个容器内切换多个组件,每次只显示一个组件。 使用场景:适合实现多步表单或选项卡式界面,每张卡片代表一个页面。 GroupLayout(组布局): 描述:组件根据指定的水平和垂直分组对齐,通常与布局设计器一起使用。 使用场景:适合需要精确控制组件对齐和排列的复杂界面。简单搭建一下布局注意要给最顶上的JPanel一个field name属性然后在我们的类中提供一个set方法新建一个工厂方法实现 ToolWindowFactory 接口public class WindowFactory implements ToolWindowFactory { @Override public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) { // 实例化窗口类 CodeWindow codeWindow = new CodeWindow(); // 获取上下文 ContentFactory cf = ContentFactory.getInstance(); Content content = cf.createContent(codeWindow.getRoot(), "", false); toolWindow.getContentManager().addContent(content); } } 在文件将工厂类注册 <extensions defaultExtensionNs="com.intellij"> <!-- 创建一个窗体 --> <toolWindow factoryClass="com.suxii.WindowFactory" id="super code" anchor="right"/> </extensions>factoryClass为工厂类,anchor是窗体显示的位置,inco属性是设置图标,不设置使用默认的运行插件项目双击 Run Plugin 这时候会重新启动一个idea,等待加载完成可用看到插件已经显示出来了项目打包双击jar任务生成的文件在build目录下的libs里本地安装插件打开插件市场,选择从磁盘安装,找到我们打包的插件安装即可已经按照成功了{dotted startColor="#ff6c6c" endColor="#1989fa"/}这里还会有个问题,在设置完field name属性之后的按钮,在设置了点击事件后,按钮的文字就不显示了 copyBtn.setAction(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { // 点击事件 } })解决方案:AbstractAction copyAction = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { // 点击事件 } }; copyAction.putValue(Action.NAME,"复制");
2024年08月16日
78 阅读
0 评论
3 点赞
2024-08-13
js逆向xhs(二)
分享另一种思路,要明确我们最终的目的都是要拿到加密函数的返回值,这期间做的任何准备都是为了加密值做服务的,所以可以使用websocket作为通信,间接调用加密函数,拿到加密值使用netty作为ws服务器public class WebSocketServer { public static final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); public static void main(String[] args) throws Exception { NioEventLoopGroup bossGroup = new NioEventLoopGroup(); NioEventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { ChannelPipeline p = ch.pipeline(); p.addLast(new HttpServerCodec()); p.addLast(new HttpObjectAggregator(65536)); p.addLast(new HttpContentCompressor()); p.addLast(new WebSocketServerProtocolHandler("/")); p.addLast(new WebSocketFrameHandler()); } }); System.out.println("server run ..."); ChannelFuture future = bootstrap.bind(8080).sync(); future.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } static class WebSocketFrameHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { super.channelActive(ctx); System.out.println(ctx.channel().remoteAddress()+":connect"); channelGroup.add(ctx.channel()); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { super.channelInactive(ctx); channelGroup.remove(ctx.channel()); System.out.println(ctx.channel().remoteAddress()+":disconnect"); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { if (msg instanceof WebSocketFrame) { WebSocketFrame frame = (WebSocketFrame) msg; if (frame instanceof TextWebSocketFrame) { if (channelGroup.size()<2) return; channelGroup.stream().filter(ch->ch != ctx.channel()).forEach(ch->ch.writeAndFlush(frame)); } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { System.out.println(ctx.channel().remoteAddress()+"连接出错:"+cause.getMessage()); ctx.close(); } } }在浏览器环境运行jsxhs这里由于用到了window全局变量储存加密函数,所以我们只要在控制台或者代码段地方执行我们直接的代码逻辑,因为是在xhs的网站作用域下,是可以直接使用全局变量的const singletonFunction = (function() { let instance; let executed = false; function createInstance() { if (!executed) { var sgin = window._webmsxyw; const ws = new WebSocket('ws://127.0.0.1:8080/'); ws.onopen = function(evt){ ws.send("我已连接,状态良好"); console.log("我已连接,状态良好"); } ws.onmessage = function(evt){ var data = JSON.parse(evt.data); console.log(data,data.c,data.i); ws.send(JSON.stringify(sgin(data.c,data.i))); } executed = true; } } return function() { if (!instance) { instance = createInstance; } return instance; }; })(); singletonFunction()();这里注入的方案有很多,也可以使用代理添加我们自己的逻辑,或者编写油猴脚本也是可以的。说一下手动注入吧,原理都大差不差点开全部选项,选择替换点击选择放置替换的文件夹选择文件夹后允许,勾选上本地替换依旧是找到加密函数的位置,通过搜索匹配右键该文件,选择替换内容将我们的代码添加到指定位置即可现在保存再刷新网页,就会走我们本地的js代码启动服务端先用websocket在线测试网站查看运行情况https://www.wetools.com/websocket是能成功拿到加密后的数据的接下来就是在项目中拿到这里加密的内容了使用okhttp连接ws服务器def client = new OkHttpClient() def request = new Request.Builder().url("ws://localhost:8080").build() client.newWebSocket(request,new WebSocketListener() { @Override void onMessage(@NotNull WebSocket webSocket, @NotNull String text) { super.onMessage(webSocket, text) println text } })现在加密值也拿到了,带上加密值正常请求接口即可
2024年08月13日
118 阅读
0 评论
3 点赞
1
...
7
8
9
...
21