Java -- 初级开发者不经常宠幸的重点 悠悠 2023-05-21 08:47 135阅读 0赞 ### 【导入】 ### * 本篇讲解的一些是作为新手入职之后不经常用到的,但是可能会面试被问到,因此需要理解,以后用到的时候在深入研究。但是不作为现阶段研究的重点,切勿跑偏方向; * 到目前为止,java基础的学习就到这个地方,没有写的很全面,还需要后期的补充。有蒙圈的哥们,可以自行复习,接下来就是一点点的web前端知识,还有Maven的研究了。 * 一起加油!!!ヾ(◍°∇°◍)ノ゙ ![在这里插入图片描述][20200426182351152.jpg_pic_center] ### 【目录】 ### * 一、注解 * 1、概述 * 2、JDK注解 * 3、元注解 * @Target ElementType.class * @Retention RetentionPolicy.class * 4、自定义注解 * 二、反射 * 1、概述 * 2、为什么需要反射 * 3、反射Class对象 * 4、常用方法 * 5、反射的应用 * 5.1 获取类对象 * 5.2 获取构造方法 * 5.3 获取成员方法 * 5.4 获取成员变量 * 5.5 创建对象 * 6、暴力反射 * 三、内部类 * 1、概述 * 2、特点 * 3、成员内部类 * 被private修饰 * 被static修饰 * 4、匿名内部类 * 四、Socket编程 * 1、概述 * 2、服务器端 * 3、客户端 * 4、测试案例 ## 一、注解 ## #### 1、概述 #### 1. 注解很厉害,它可以增强我们的java代码,同时利用反射技术可以扩充实现很多功能。它们被广泛应用于三大框架底层。传统我们通过xml文本文件声明方式,而现在最主流的开发都是基于注解方式,代码量少,框架可以根据注解去自动生成很多代码,从而减少代码量,程序更易读。例如最火爆的SpringBoot就完全基于注解技术实现; 2. 注解设计非常精巧,初学时觉得很另类甚至多余,甚至垃圾。有了java代码干嘛还要有@注解呢?但熟练之后你会赞叹,它竟然可以超越java代码的功能,让java代码瞬间变得强大。大家慢慢体会吧; 3. 常见的元注解:@Target、@Retention,jdk提供将来描述我们自定义的注解的注解。听起来好绕,别着急,做两个例子,立刻清晰。现在现有“元注解”这个概念。 **注解分类** * JDK自带注解 * 元注解 * 自定义注解 #### 2、JDK注解 #### JDK注解的注解,就**5**个: * `@Override` * `@Deprecated`标记就表明这个方法已经过时了,但我就要用,别提示我过期 * `@SuppressWarnings(“deprecation”)` 忽略警告 * `@SafeVarargs` jdk1.7出现,堆污染,不常用 * `@FunctionallInterface` jdk1.8出现,配合函数式编程拉姆达表达式,不常用 > **常用的`@Override` ,标志着该方法是一个重写方法** #### 3、元注解 #### 描述注解的注解,就5个: * `@Target` 注解用在哪里:类上、方法上、属性上;**值都被维护在ElementType类中** * `@Retention` 注解的生命周期:源文件中、class文件中、运行中;**值都被维护在RetentionPolicy类中;** * `@Inherited` 允许子注解继承 * `@Documented` 生成javadoc时会包含注解,不常用 * `@Repeatable`注解为可重复类型注解,可以在同一个地方多次使用,不常用 > 1. **常用的`@Target` 和 `@Retention`** > 2. **如果觉得这十个还不够用,还可以自定义注解** ##### 1.3.1 @Target ElementType.class ##### 描述注解的使用范围: * `ElementType.ANNOTATION_TYPE` \------> 应用于注释类型 * `ElementType.CONSTRUCTOR` \------> 应用于构造函数 * `ElementType.FIELD` \------> 应用于字段或属性 * `ElementType.LOCAL_VARIABLE` \------> 应用于局部变量 * `ElementType.METHOD` \------> 应用于方法级 * `ElementType.PACKAGE` \------> 应用于包声明 * `ElementType.PARAMETER` \------> 应用于方法的参数 * `ElementType.TYPE` \------> 应用于类的元素 ##### 1.3.2 @Retention RetentionPolicy.class ##### * 定义了该注解被保留的时间长短,某些注解仅出现在源代码中,而被编译器丢弃; * 而另一些却被编译在class文件中; 编译在class文件中的注解可能会被虚拟机忽略,而另一些在class被装载时将被读取。 * 为何要分有没有呢?没有时,反射就拿不到,从而就无法去识别处理。 * `SOURCE` \------> 在源文件中有效(即源文件保留) * `CLASS` \------> 在class文件中有效(即class保留) * `RUNTIME` \------> 在运行时有效(即运行时保留) #### 4、自定义注解 #### package cn.tedu.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //这个类用来测试自定义注解 public class Test_Annotation { public static void main(String[] args) { } } //1、创建自定义注解:语法:@interface 注解名 //2、@Target指定注解位置 -- ElementType.TYPE //3、@Retention指定注解的生命周期 -- RetentionPolicy.SOURCE //@Target(ElementType.TYPE)//2、指定注解的位置 @Target({ ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.SOURCE) @interface Test{ //5、给注解添加属性 -- 注解的语法和java略有不同 // String name(); String name() default ""; String value()default "";//8、特殊属性赋值时可以简写 } //4、使用自定义的注解Test //@Test(name = "Daniel")//6、使用Test注解时,同时给name属性赋值 //7、如果name属性有了默认值,我们使用就可以省略赋值 //@Test//要是想修改,可以继续赋值//@Test(name = "Daniel") @Test("hello")//8.1如果给value属性赋值,可以简写 class hello{ // @Test The annotation @Test is disallowed for this location String name; @Test public void method() { System.out.println(123); } } ## 二、反射 ## #### 1、概述 #### * **Reflection(反射)** 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,也有称作“自省”。反射非常强大,它甚至能直接操作程序的私有属性。我们前面学习都有一个概念,private的只能类内部访问,外部是不行的,但这个规定被反射赤裸裸的打破了; * 反射就像一面镜子,它可以在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段、方法、构造器等部分。 #### 2、为什么需要反射 #### * 好好的我们new User(); 不是很好,为什么要去通过反射创建对象呢? * 那我要问你个问题了,你为什么要去餐馆吃饭呢? * 例如:我们要吃个牛排大餐,如果我们自己创建,就什么都得管理。 * 好处是,每一步做什么我都很清晰,坏处是什么都得自己实现,那不是累死了。牛接生你管,吃什么你管,屠宰你管,运输你管,冷藏你管,烹饪你管,上桌你管。就拿做菜来说,你能有特级厨师做的好? * 那怎么办呢?有句话说的好,专业的事情交给专业的人做,饲养交给农场主,屠宰交给刽子手,烹饪交给特级厨师。那我们干嘛呢? * 我们翘起二郎腿直接拿过来吃就好了。 * 再者,饭店把东西做好,不能扔到地上,我们去捡着吃吧,那不是都成原始人了。那怎么办呢?很简单,把做好的东西放在一个容器中吧,如把牛排放在盘子里。 * 在开发的世界里,spring就是专业的组织,它来帮我们创建对象,管理对象。我们不在new对象,而直接从spring提供的容器中beans获取即可。Beans底层其实就是一个`Map<String,Object>`,最终通过`getBean(“user”)`来获取。而这其中最核心的实现就是利用反射技术。 * **总结一句,类不是你创建的,是你同事或者直接是第三方公司,此时你要或得这个类的底层功能调用,就需要反射技术实现。有点抽象,别着急,我们做个案例,你就立马清晰。** #### 3、反射Class对象 #### 反射对象有三种方式 1. `Class.forName(“类的全路径”);` 2. `类名.class` 3. `对象.getClass();` 测试案例: package cn.tedu.reflection; //这个类用来测试 -- 反射 public class Test_Reflection { public static void main(String[] args) throws ClassNotFoundException { //获取class对象 Class class1 = Class.forName("cn.tedu.reflection.Test_Reflection");//参数是 类的全路径 = 包名.类名 Class class2 = Test_Reflection.class; // Test_Reflection t = new Test_Reflection(); new Test_Reflection().getClass();//匿名内部类 System.out.println(class1); System.out.println(class2); System.out.println(); } } > 复制包名全路径的方法:鼠标放在类名处,右键选择Copy Qualified Name,即可复制全路径 #### 4、常用方法 #### * **获得包名、类名** clazz.getPackage().getName()//包名 clazz.getSimpleName()//类名 clazz.getName()//完整类名 * **!!成员变量定义信息** getFields()//获得所有公开的成员变量,包括继承的变量 getDeclaredFields()//获得本类定义的成员变量,包括私有,不包括继承的变量 getField(变量名) getDeclaredField(变量名) * **!!构造方法定义信息** getConstructor(参数类型列表)//获得公开的构造方法 getConstructors()//获得所有公开的构造方法 getDeclaredConstructors()//获得所有构造方法,包括私有 getDeclaredConstructor(int.class, String.class) * **方法定义信息** getMethods()//获得所有可见的方法,包括继承的方法 getMethod(方法名,参数类型列表) getDeclaredMethods()//获得本类定义的方法,包括私有,不包括继承的方法 getDeclaredMethod(方法名, int.class, String.class) * **反射新建实例** c.newInstance();//执行无参构造 c.newInstance(6, "abc");//执行有参构造 c.getConstructor(int.class, String.class); //执行含参构造,获取构造方法 * **反射调用成员变量** c.getDeclaredField(变量名); //获取变量 c.setAccessible(true); //使私有成员允许访问 f.set(实例, 值); //为指定实例的变量赋值,静态变量,第一参数给 null f.get(实例); //访问指定实例的变量的值,静态变量,第一参数给 null * **反射调用成员方法** 获取方法 Method m = c.getDeclaredMethod(方法名, 参数类型列表); m.setAccessible(true) ;//使私有方法允许被调用 m.invoke(实例, 参数数据) ;//让指定的实例来执行该方法 #### 5、反射的应用 #### ###### 5.1 获取类对象 ###### //Junit单元测试方法:@Test + void + 没有参数 //运行:必须选中方法名,右键,run as,Junit test... //反射Class对象 @Test public void showClass() throws ClassNotFoundException { Class class1 = Student.class; Class class2 = Class.forName("cn.tedu.reflection.Student"); Student student = new Student(); Class class3 = student.getClass(); System.out.println(class1); System.out.println(class2); System.out.println(class3); System.out.println(); } ###### 5.2 获取构造方法 ###### //获取学生类中的构造方法 @Test public void showConstructor() { //1、获取class对象 Class<?> class1 = Student.class; //2、调用方法 Constructor<?>[] cs = class1.getConstructors(); //3、遍历数组 for (Constructor<?> constructor: cs) { //4、获取方法名 String name = constructor.getName(); //5、获取参数类型 Class<?>[] cls = constructor.getParameterTypes(); System.out.println(Arrays.toString(cls)); } System.out.println("******************"); } ###### 5.3 获取成员方法 ###### //获取学生类中的成员方法 @Test public void showMethod() { //1、获取class对象 Class<?> class1 = Student.class; //2、调用方法 Method[] ms = class1.getMethods(); //3、遍历数组 for (Method method : ms) { //4、获取方法名 String name = method.getName(); System.out.println(name); //5、获取方法有没有参数 Class<?>[] cls = method.getParameterTypes(); System.out.println(Arrays.toString(cls)); } System.out.println("======="); } ###### 5.4 获取成员变量 ###### //获取学生类中的成员变量 @Test public void showFileds() { //1、获取class对象 Class<?> class1 = Student.class; //2、获取所有 公共的 属性 Field[] fs = class1.getFields(); //3、遍历数组 for (Field f : fs) { //4、获取变量名 String name = f.getName(); System.out.println(name); //5、获取类型 String type = f.getType().getName(); System.out.println(type); System.out.println("++++++++++"); } } ###### 5.5 创建对象 ###### //利用反射创建对象 @Test public void showObject() throws Exception { //1、获取class对象 Class<?> class1 = Student.class; //2、利用反射好,让反射创建对象 Object obj = class1.newInstance();//触发了无参构造 System.out.println(obj);//cn.tedu.reflection.Student@b7dd107 //含参构造的触发 //指定你想要触发哪个含参构造 class1.getConstructor(String.class);//触发string类型的含参构造 class1.getConstructor(int.class);//触发int类型的含参构造 Constructor<?> c = class1.getConstructor(String.class,int.class); Object obj2 = c.newInstance("兔八哥",20); //Student [name=兔八哥, age=20] System.out.println(obj2); System.out.println("--------------"); } * 附带测试总代码: 1、先创建一个Student类 package cn.tedu.reflection; public class Student { public Student() { } public Student(String name) { this.name = name; } public Student(int age) { this.age = age; } public Student(String name,int age) { this.name = name; this.age = age; } public String name; public int age; public void save() { System.out.println("save()......"); } public void show(int num) { System.out.println("show()..."+num); } //重写toString():为了方便查看对象的属性值而不是地址值 @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } } 2、在创建一个测试类 ---- Junit单元测试 package cn.tedu.reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; import org.junit.Test; //这个类用来测试,反射获取学生类里的所有数据 public class Test_ReflectionStudent { // public static void main(String[] args) { // // } //利用反射创建对象 @Test public void showObject() throws Exception { //1、获取class对象 Class<?> class1 = Student.class; //2、利用反射好,让反射创建对象 Object obj = class1.newInstance();//触发了无参构造 System.out.println(obj);//cn.tedu.reflection.Student@b7dd107 //含参构造的触发 //指定你想要触发哪个含参构造 class1.getConstructor(String.class);//触发string类型的含参构造 class1.getConstructor(int.class);//触发int类型的含参构造 Constructor<?> c = class1.getConstructor(String.class,int.class); Object obj2 = c.newInstance("兔八哥",20); //Student [name=兔八哥, age=20] System.out.println(obj2); System.out.println("--------------"); } //获取学生类中的成员变量 @Test public void showFileds() { //1、获取class对象 Class<?> class1 = Student.class; //2、获取所有 公共的 属性 Field[] fs = class1.getFields(); //3、遍历数组 for (Field f : fs) { //4、获取变量名 String name = f.getName(); System.out.println(name); //5、获取类型 String type = f.getType().getName(); System.out.println(type); System.out.println("++++++++++"); } } //获取学生类中的构造方法 @Test public void showConstructor() { //1、获取class对象 Class<?> class1 = Student.class; //2、调用方法 Constructor<?>[] cs = class1.getConstructors(); //3、遍历数组 for (Constructor<?> constructor: cs) { //4、获取方法名 String name = constructor.getName(); //5、获取参数类型 Class<?>[] cls = constructor.getParameterTypes(); System.out.println(Arrays.toString(cls)); } System.out.println("******************"); } //Junit单元测试方法:@Test + void + 没有参数 //运行:必须选中方法名,右键,run as,Junit test... //反射Class对象 @Test public void showClass() throws ClassNotFoundException { Class class1 = Student.class; Class class2 = Class.forName("cn.tedu.reflection.Student"); Student student = new Student(); Class class3 = student.getClass(); System.out.println(class1); System.out.println(class2); System.out.println(class3); System.out.println(); } //获取学生类中的成员方法 @Test public void showMethod() { //1、获取class对象 Class<?> class1 = Student.class; //2、调用方法 Method[] ms = class1.getMethods(); //3、遍历数组 for (Method method : ms) { //4、获取方法名 String name = method.getName(); System.out.println(name); //5、获取方法有没有参数 Class<?>[] cls = method.getParameterTypes(); System.out.println(Arrays.toString(cls)); } System.out.println("======="); } } 3、控制台显示: class cn.tedu.reflection.Student class cn.tedu.reflection.Student class cn.tedu.reflection.Student name java.lang.String ++++++++++ age int ++++++++++ [class java.lang.String, int] [int] [class java.lang.String] [] ****************** toString [] save [] show [int] wait [] wait [long, int] wait [long] equals [class java.lang.Object] hashCode [] getClass [] notify [] notifyAll [] ======= Student [name=null, age=0] Student [name=兔八哥, age=20] -------------- #### 6、暴力反射 #### 指可以将程序中的私有的属性或者方法通过反射技术,暴力的获取到资源。需要使用的常见方法如下: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxMTgwODgxNDAyNQ_size_16_color_FFFFFF_t_70] * 测试案例 1、创建Person类 package cn.tedu.reflection; //这个类用来测试暴力反射 public class Person { private String name = "jack"; private int age = 10; private void show() { System.out.println("show()..."); } private void test(int a) { System.out.println("test()..."+a); } } 2、测试暴力反射 package cn.tedu.reflection; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; import org.junit.Test; //这个类用来测试暴力反射person public class Test_ReflectionPerson { //暴力反射成员方法 @Test public void showMethod() throws Exception { //1、获取class对象 Class<?> class1 = Class.forName("cn.tedu.reflection.Person"); //2、获取所有的方法们 // class1.getMethod();// 反射 公共的 资源 Method[] ms = class1.getDeclaredMethods();//暴力反射 //getDeclaredMethods();//暴力反射 -- 可以获取公共的或者私有的方法 //3、循环遍历数组 for (Method m : ms) { String name = m.getName(); System.out.println(name); Class<?>[] cls = m.getParameterTypes(); System.out.println(Arrays.toString(cls)); } //4、获取 单个 方法 -- 私有 //getDeclaredMethod(m,n); m是想要执行的方法名,n是方法需要的参数类型 Method method = class1.getDeclaredMethod("show",null); //5、如何执行show() //invoke(m, n);//m是想让哪个对象执行方法,n是方法需要的参数 //!!设置私有可见 method.setAccessible(true);//必须有这句代码 Object obj = class1.newInstance(); method.invoke(obj, null); } //暴力反射成员变量 public void showFields() throws Exception { //1、获取Class对象 Class<?> class1 = Class.forName("cn.tedu.reflection.Preson"); //2、暴力获取 变量 Field[] fs = class1.getDeclaredFields(); //获取变量类型 Field f = class1.getDeclaredField("name");//获取一个,传入属性名 String type = f.getType().getName();//获取变量类型 System.out.println(type); //设置私有可见 f.setAccessible(true); Object obj = class1.newInstance(); //设置私有属性的值 //set(m, n); -- m是要是指哪个对象名,n是要设置的值 f.set(obj, "大头"); //获取属性的值 Object value = f.get(obj);//参数是要获取哪个对象的name属性的值 System.out.println(value);//属性的值 } } 3、控制台显示 test [int] show [] show()... ## 三、内部类 ## #### 1、概述 #### * 如果一个类存在的意义就是为指定的另一个类,可以把这个类放入另一个类的内部。就是把类定义在类的内部的情况就可以形成内部类的形式。 * A类中又定义了B类,B类就是内部类。B类可以当做A类的一个成员看待。 格式: class A{ //外部类 class B{ //内部类:可以看做是外部类的成员 //变量+方法 } } > 位置不同,内部类的名字和作用就不同。 > 如果是在成员位置(类里方法外)- 成员内部类 ---- 用!! > 如果是在局部位置(方法里)-局部内部类 ---- 不用!! > 匿名内部类 – 最常用!! #### 2、特点 #### * 内部类可以直接访问外部类中的成员,包括私有成员; * 外部类要访问内部类的成员,必须要建立内部类的对象; * 在成员位置的内部类是成员内部类; * 在局部位置的内部类是局部内部类; #### 3、成员内部类:在成员位置 #### 1、定义内部类 package cn.tedu.innerclass; //这个类用来定义内部类 public class InnerClass { // int age; // private int age = 10; static private int age = 10; public void save() { System.out.println("Innerclass.save()"); // get();//未定义 //特点2:外部类想要使用内部类成员 -- 必须创建内部类对象 Inner in2 = new Inner(); in2.get(); System.out.println(in2.name); } //成员内部类 // private class Inner{ // String name = "大头"; // public void get() { // //特点1:内部类可以使用所有外部类成员 save(); // System.out.println(age); // System.out.println("惊雷!!"); // } // } static class Inner{ static int sum = 30; String name = "大头"; public void get() { //特点1:内部类可以使用所有外部类成员 // save(); System.out.println(age); System.out.println("惊雷!!"); } } } 2、测试内部类 package cn.tedu.innerclass; //这个类用来测试内部类 public class Test_InnerClass { public static void main(String[] args) { //1、想办法 使用 内部类的资源 -- 创建内部类对象 //外部类.内部类 变量名 = 外部类对象.内部类对象 // InnerClass.Inner in = new InnerClass().new Inner(); // in.get(); // System.out.println(in.name); //2、当内部类被private修饰后,我们无法直接访问内部类资源 //需要访问外部类的资源来间接实现内部类的资源 InnerClass in = new InnerClass(); in.save(); System.out.println(); //3、当内部类被静态static修饰后,可以直接被类名调用 //创建内部类对象 // InnerClass.Inner in2 = new InnerClass().new Inner(); InnerClass.Inner in2 = new InnerClass.Inner(); in2.get(); System.out.println(in2.name); //4、静态的内部类里的静态资源 -- 链式编程 System.out.println(InnerClass.Inner.sum); } } ###### 3.1 被private修饰 ###### private class Inner{ String name = "大头"; public void get() { //特点1:内部类可以使用所有外部类成员 // save(); System.out.println(age); System.out.println("惊雷!!"); } } ###### 3.2 被static修饰 ###### static class Inner{ static int sum = 30; String name = "大头"; public void get() { //特点1:内部类可以使用所有外部类成员 // save(); System.out.println(age); System.out.println("惊雷!!"); } } #### 4、匿名内部类 #### package cn.tedu.innerclass; //这个类用来测试 -- 匿名内部类 public class Test2_InnerClass2 { public static void main(String[] args) { new Xin();//匿名对象 //2、接口可以创建对象吗? -- 不可以 //如果同时使用了匿名对象和匿名内部类是可以直接new的,就相当于创建了接口的实现类 //匿名的好处是:用起来方便。坏处是:一次只执行一个任务 new Inter1() { @Override public void save() { System.out.println("save()"); } @Override public void get() { System.out.println("get()"); } }.get();//3、触发方法的执行 //5、抽象类直接new可以吗? -- 不可以 new AbstractDemo() { @Override public void sleep() { System.out.println("sleep()..."); } }.sleep();//6、触发方法 } } //4、定义抽象类 abstract class AbstractDemo{ public void eat() { System.out.println("eat()..."); } abstract public void sleep(); } //1、定义接口 interface Inter1{ void save(); void get(); } class Xin{ } 控制台显示: get() sleep()... ## 四、Socket编程 ## #### 1、概述 #### * 也叫套接字编程,是一个抽象层。 * 应用程序可以通过它发送或接收数据,可对其像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口与协议的组合。 * Socket就是为网络编程提供的一种机制 / 通信的两端都有Socket * 网络通信其实就是Socket间的通信 / 数据在两个Socket间通过IO传输 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxMTgwODgxNDAyNQ_size_16_color_FFFFFF_t_70 1] #### 2、服务器端 #### * 在服务器端,选择一个端口号,在指定端口上等待客户端发起连接。 1. 创建对象 `ServerSocket(int port)` 2. 常用方法 `Socket accept()` 3. 侦听并接受到此套接字的连接。 `void close()` 4. 关闭此套接字。 ServerSocket ss = new ServerSocket(9000);//启动服务 Socket socket = ss.accept();//等待客户端发起连接,并建立连接通道 #### 3、客户端 #### 1. 创建对象 `Socket(String host, int port)` 创建一个流套接字并将其连接到指定主机上的指定端口号。 2. 常用方法 `void close()` 3. 关闭此套接字。 //新建Socket对象,连接指定ip的服务器的指定端口 Socket s = new Socket(ip, port); //从Socket获取双向的流 InputStream in = s.getInputStream(); OutputStream out = s.getOutputStream(); #### 4、测试案例 #### 需求:-- 服务器端接收客户端发来的hello,并给客户端响应hello * 服务器端 > 说明其中,server端的accept()是阻塞的,客户端不连接,服务器不执行后面流程。 > in.read()也是阻塞的,读不到就死等。 package cn.tedu.net; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; //这是socket编程的服务器端 public class Server { public static void main(String[] args) throws Exception { //1、创建服务器对象,表示在该端口上,等待客户端连接请求 //参数是端口号0-65535,其中0-1024被系统占用 ServerSocket ss = new ServerSocket(9000); //2、开始接受客户端的请求,并建立了数据传输通道socket Socket socket = ss.accept(); System.out.println("恭喜您,连接成功111"); //3、接收客户端发来的数据 InputStream in = socket.getInputStream(); //客户端发来5个字节。循环读取5次。 for (int i = 0; i < 5; i++) { // int b = in.read();//不能读到整数,我就要字符 char c = (char)in.read(); System.out.print(c);//同行展示 } //4、服务端给客户端发送数据 -- out OutputStream out = socket.getOutputStream(); //5、开始写出数据 out.write("world".getBytes()); out.flush(); } } * 客户端 package cn.tedu.net; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; //这是socket编程的客户端 public class Client { public static void main(String[] args) throws Exception { //1、创建客户端对象,连接指定的服务器 //参数是服务器的IP和服务器的端口 //IP地址如果是访问你这台电脑IP是固定值127.0.0.1/localhost //IP地址如果是在工作中,就应该写真实的服务器的IP // Socket sc = new Socket("192.168.1.50",20235); Socket so = new Socket("127.0.0.1",9000); //2、给服务器发送数据 -- out OutputStream out = so.getOutputStream(); //3、开始写出数据 out.write("hello".getBytes());//参数需要的是byte out.flush(); //4、客户端读取服务器发回来的数据 -- in InputStream in = so.getInputStream(); for (int i = 0; i < 5; i++) { char c = (char) in.read(); System.out.print(c); } } } * 测试 1. 先启动服务器端 2. 在启动客户端 3. 服务器端 或者 客户端 只能启动一次。多次就会抛出端口占用异常:`java.net.BindException: Address already in use: JVM_Bind` 4. 注意启动顺序,如果反了,客户端无法连接服务器,会抛出异常: `java.net.ConnectException: Connection refused: connect` ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxMTgwODgxNDAyNQ_size_16_color_FFFFFF_t_70_pic_center] ### 【总结】 ### * 接下来需要做一个系统的总结了,有针对性的进行总结,比如面试重点、易混点… * 推荐总结:数组 + OOP + IO + 集合 * 可以稍微了解一下算法:冒泡排序(复习数组) + jdk新特性 * 又到了兔八哥说再见的时候了,┏(^0^)┛!!!点赞加关注,学习不迷路; * 我们下期再见!!! [20200426182351152.jpg_pic_center]: /images/20230521/37698f883f38490e96c0ffadfd2c340e.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxMTgwODgxNDAyNQ_size_16_color_FFFFFF_t_70]: /images/20230521/c99db40ecf1741358e9cb08b9bc74094.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxMTgwODgxNDAyNQ_size_16_color_FFFFFF_t_70 1]: /images/20230521/ebec13498a3b494a990818f6d4796b71.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxMTgwODgxNDAyNQ_size_16_color_FFFFFF_t_70_pic_center]: /images/20230521/0f55f4a5f5a942399ec3db3793304d8e.png
相关 初级开发者:理解Java内存回收的实例 Java内存回收,通常指的是垃圾回收(Garbage Collection,GC),是Java自动管理内存的一个重要特性。它帮助开发者自动释放不再使用的对象所占用的内存,避免内 逃离我推掉我的手/ 2024年11月14日 04:51/ 0 赞/ 1 阅读
相关 初级开发者:未理解的NullPointerException `NullPointerException` 是 Java编程语言中常见的一种运行时异常,它发生在尝试使用 `null`值的对象进行操作时。例如,当你尝试调用一个 `null` 忘是亡心i/ 2024年10月31日 08:09/ 0 赞/ 13 阅读
相关 初级开发者:Java异常处理示例 在Java编程中,异常处理是一种机制,用于在程序执行过程中遇到错误或意外情况时,能优雅地捕获、处理和恢复系统状态。 以下是一个简单的Java异常处理示例: ```java 浅浅的花香味﹌/ 2024年10月23日 03:30/ 0 赞/ 29 阅读
相关 初级Java开发者:数组越界的问题分析 在初级Java开发过程中,数组越界是一个常见的错误。这种问题主要源于对数组概念和操作的理解不足。 1. **理解数组的索引范围**: 在Java中,一个数组通常有一个固 逃离我推掉我的手/ 2024年10月11日 09:39/ 0 赞/ 53 阅读
相关 初级开发者:Java中的内存泄漏问题 内存泄漏在任何编程语言中都可能遇到,包括Java。下面简单解释一下Java中的内存泄漏问题: 1. **对象引用**:如果一个对象被创建后仍然有其他的变量或者方法去引用它,那 傷城~/ 2024年10月08日 00:15/ 0 赞/ 39 阅读
相关 初级开发者:Java中异常处理的问题 在Java编程中,异常处理是一个至关重要的概念。当你编写代码时,可能会遇到各种预期之外的情况,这时候就需要通过异常处理来优雅地处理这些错误。 以下是一些基本的Java异常处理 ╰半夏微凉°/ 2024年09月27日 22:09/ 0 赞/ 43 阅读
相关 初级开发者:Java内存泄漏排查 作为初级开发者,如果你遇到Java内存泄漏问题,可以通过以下步骤进行排查: 1. **理解内存泄漏**: - 内存泄漏是指程序申请了内存但未能释放。 - Java ╰半橙微兮°/ 2024年09月25日 18:24/ 0 赞/ 46 阅读
相关 初级Java开发者常见的内存溢出问题 初级Java开发者在开发过程中可能会遇到以下几种常见的内存溢出问题: 1. 数组或列表过长:如果动态创建的数组、List等容器元素个数超过了系统允许的最大值,就会发生内存溢出 ﹏ヽ暗。殇╰゛Y/ 2024年09月17日 15:51/ 0 赞/ 52 阅读
相关 Java -- 初级开发者不经常宠幸的重点 【导入】 本篇讲解的一些是作为新手入职之后不经常用到的,但是可能会面试被问到,因此需要理解,以后用到的时候在深入研究。但是不作为现阶段研究的重点,切勿跑偏方向; 悠悠/ 2023年05月21日 08:47/ 0 赞/ 136 阅读
还没有评论,来说两句吧...