menu ChaYedan
Java基础知识(五)
445 浏览 | 2020-04-19 | 阅读时间: 约 8 分钟 | 分类: Java | 标签: Java
请注意,本文编写于 893 天前,最后修改于 893 天前,其中某些信息可能已经过时。

网络编程

软件结构

  • C/S结构 :全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件。
  • B/S结构 :全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等。

两种架构各有优势,但是无论哪种架构,都离不开网络的支持。网络编程,就是在一定的协议下,实现两台计算机
的通信的程序。

网络通信协议

  • 网络通信协议:通信协议是对计算机必须遵守的规则,只有遵守这些规则,计算机之间才能进行通信。这就
    好比在道路中行驶的汽车一定要遵守交通规则一样,协议中对数据的传输格式、传输速率、传输步骤等做了

统一规定,通信双方必须同时遵守,最终完成数据交换。

  • TCP/IP协议: 传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol),是
    Internet最基本、最广泛的协议。它定义了计算机如何连入因特网,以及数据如何在它们之间传输的标准。它

的内部包含一系列的用于处理数据通信的协议,并采用了4层的分层模型,每一层都呼叫它的下一层所提供的
协议来完成自己的需求。

协议分类

通信的协议还是比较复杂的, java.net 包中包含的类和接口,它们提供低层次的通信细节。我们可以直接使用这
些类和接口,来专注于网络程序开发,而不用考虑通信的细节。

java.net 包中提供了两种常见的网络协议的支持:

  • TCP:传输控制协议 (Transmission Control Protocol)。TCP协议是面向连接的通信协议,即传输数据之前,
    在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。
  • UDP:用户数据报协议(User Datagram Protocol)。UDP协议是一个面向无连接的协议。传输数据时,不需要建立连接,不管对方端服务是否启动,直接将数据、数据源和目的地都封装在数据包中,直接发送。每个数据包的大小限制在64k以内。它是不可靠协议,因为无连接,所以传输速度快,但是容易丢失数据。日常应用中,例如视频会议、QQ聊天等。每次发送的数据最大为64kb

TCP

TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server)。

步骤:

  1. 服务端程序,需要事先启动,等待客户端的连接。
  2. 客户端主动连接服务器端,连接成功才能通信。服务端不可以主动连接客户端。

在Java中,提供了两个类用于实现TCP通信程序:

  1. 客户端: java.net.Socket 类表示。创建 Socket 对象,向服务端发出连接请求,服务端响应请求,两者建
    立连接开始通信。
  2. 服务端: java.net.ServerSocket 类表示。创建 ServerSocket 对象,相当于开启一个服务,并等待客户端
    的连接。
Socket类

Socket 类:该类实现客户端套接字,套接字指的是两台设备之间通讯的端点。

构造方法

public Socket(String host, int port) :创建套接字对象并将其连接到指定主机上的指定端口号。如果指
定的host是null ,则相当于指定地址为回送地址。

成员方法

public InputStream getInputStream() : 返回此套接字的输入流。

  • 如果此Scoket具有相关联的通道,则生成的InputStream 的所有操作也关联该通道。
  • 关闭生成的InputStream也将关闭相关的Socket。

public OutputStream getOutputStream() : 返回此套接字的输出流。

  • 如果此Scoket具有相关联的通道,则生成的OutputStream 的所有操作也关联该通道。
  • 关闭生成的OutputStream也将关闭相关的Socket。

public void close() :关闭此套接字。

  • 一旦一个socket被关闭,它不可再使用。
  • 关闭此socket也将关闭相关的InputStream和OutputStream 。

public void shutdownOutput() : 禁用此套接字的输出流。

  • 任何先前写出的数据将被发送,随后终止输出流。相当于给服务端那边发送了个EOF
ServerSocket类

ServerSocket 类:这个类实现了服务器套接字,该对象等待通过网络的请求。

构造方法

public ServerSocket(int port) :使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指
定的端口号上,参数port就是端口号。

ServerSocket server = new ServerSocket(6666);
成员方法

public Socket accept() :侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信。该方法
会一直阻塞直到建立连接。

Junit

Junit是一个Java语言的单元测试框架,属于白盒测试,简单理解为可以用于取代java的main方法。Junit属于第三
方工具,需要导入jar包后使用。

使用

  1. 编写测试类,简单理解Junit可以用于取代java的main方法
  2. 在测试类方法上添加注解 @Test
  3. @Test修饰的方法要求:public void 方法名() {…} ,方法名自定义建议test开头,没有参数。
  4. 添加Junit库到lib文件夹中,然后进行jar包关联
  5. 使用:点击方法左侧绿色箭头,执行当前方法(方法必须标记@Test)。执行结果红色:代表失败;执行结果
    绿色:代表成功

哪个方法想使用单元测试,就在方法上,添加注解: @Test

注意:

  • 该方法的返回值类型,必须写为void
  • 该方法必须没有参数列表
  • 不能用static修饰

运行:方法上右键运行,运行的是含有@Test注解的方法。类上右键运行,运行的是类当中含有@Test注解的所有方

绿条: 正常运行

红条: 出现问题,异常了

常用注解

  • @Test,用于修饰需要执行的测试方法
  • @Before,修饰的方法会在测试方法之前被自动执行
  • @After,修饰的方法会在测试方法执行之后自动被执行

另外,IDEA本身就集成了这个功能

反射

类的加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进
行初始化。

加载

  • 就是指将class文件读入内存,并为之创建一个Class对象。
  • 任何类被使用时系统都会建立一个Class对象

连接

  • 验证是否有正确的内部结构,并和其他类协调一致
  • 准备负责为类的静态成员分配内存,并设置默认初始化值
  • 解析将类的二进制数据中的符号引用替换为直接引用

初始化

详情见下面

初始化

  1. 创建类的实例
  2. 类的静态变量,或者为静态变量赋值
  3. 类的静态方法
  4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
  5. 初始化某个类的子类
  6. 直接使用java.exe命令来运行某个主类

到目前为止我们已经知道把class文件加载到内存了,那么,如果我们仅仅站在这些class文件的角度,我们如何来
使用这些class文件中的内容呢? 这就是我们反射要研究的内容。

概述

框架:半成品软件。可以在框架的基础上进行软件开发,简化编码

反射:将java代码的各个组成部分封装为其他对象,可以在程序运行过程中操作这些对象,这就是java的反射

机制,如下图。

反射的好处:

  1. 可以在程序运行过程中,操作这些对象。
  2. 可以解耦,提高程序的可扩展性。

注意:

同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的
Class对象都是同一个。

获取Class对象的方式

获取class对象方式作用应用场景
Class.forName("全类名")通过指定的字符串路径获取多用于配置文件,将类名定义在配置文件中。读取文件,加载类
类名.class通过类名的属性class获取多用于参数的传递
对象.getClass()通过对象的getClass()方法获取多用于对象的获取字节码的方式

建议使用第一种方式获取Class对象

Class对象相关方法

  1. String getSimpleName(); 获得简单类名,只是类名,没有包
    . String getName(); 获取完整类名,包含包名+类名
  2. T newInstance() ;创建此 Class 对象所表示的类的一个新实例。要求:类必须有public的无参数构造方法

Constructor类

Constructor是构造方法类,类中的每一个构造方法都是Constructor的对象,通过Constructor对象可以实例化对
象。

成员方法
  • public Constructor[] getConstructors(): 获取public修饰的所有的构造方法

      每个构造方法被封装成了一个Constructor类型的对象,被存储数组中
      注意: Constructor类,专门用来描述构造方法的
    
  • public Constructor<T> getConstructor(Class... parameterTypes): 获取指定参数类型的public修饰的构造方法

      如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。
      参数:
          Class... parameterTypes: 必须传递数据类型对应的Class对象,而且是可变参数,可以传递数组,参数列表,不传递(获取空参)
    

​ 比如: 获取 构造方法 public Person(String name, int age) { ...} 对应的Construtor对象

​ 参数列表: String.class,int.class

Constructor<?> con2 = c.getConstructor(String.class, int.class);
        System.out.println(con2);

私有方法也能通过其他方法反射出来,但最好不要这么做,因为破坏了封装性

获取步骤
  1. 获取Class类型的对象(三种方式,建议使用第三种forName)
  2. 通过Class类型的对象获取构造方法对象
利用反射得到的构造方法构造对象
  • T newInstance(Object... initargs):根据指定参数创建对象。

    public class Demo06NewInstance {
        public static void main(String[] args) throws Exception {
            //1.获取Class类型的对象(三种方式,建议使用第三种forName)
            Class<?> c = Class.forName("domain.Person");
            //2.通过Class类型的对象获取带参构造方法对象
            //获取满参构造方法对象
            Constructor<?> con = c.getConstructor(String.class, int.class);
            //3.执行带参构造方法对象,创建一个具体的对象
            Person p = (Person)con.newInstance("张三",20);
    
            System.out.println(p);
        }
    }
  • T newInstance():空参构造方法创建对象。返回值:Object类型: 被创建出来的对象,提升为Object类型

    public class Demo05NewInstance {
        public static void main(String[] args) throws Exception {
            //1.获取Class类型的对象(三种方式,建议使用第三种forName)
            //domain是包名
            Class<?> c = Class.forName("domain.Person");
    
            //2.通过Class类型的对象获取空参构造方法对象
            Constructor<?> con = c.getConstructor();
    
            //3.执行构造方法对象,创建一个具体的对象
            //执行的是空参构造方法对象,不需要传递参数
            Person p = (Person)con.newInstance();
    
            System.out.println(p);//Person{name='null', age=0}
        }
    }
  • 上面两个是Constructor类的方法,这个是Class类的方法,直接调用的空参构造

public T newInstance(): 执行空参构造方法,创建一个对象

内部原理:

              1.内部会获取空参构造方法对象,要求类中必须定义空参构造
              2.空参构造方法对象调用newInstance(Construct类中的),创建一个对象
public class Demo07NewInstance {
    public static void main(String[] args) throws Exception {
        //1.获取Class类型的对象(三种方式,建议使用第三种forName)
        Class<?> c = Class.forName("domain.Person");

        //2.java.lang.Class类 成员方法: newInstance
        Person p = (Person)c.newInstance();
        System.out.println(p);
    }
}

Method类

Method是方法类,类中的每一个方法都是Method的对象,通过Method对象可以调用方法。

成员方法
  • public Method[] getMethods(): 获取所有public修饰的成员方法,包含继承下来的每个成员方法被封装成了一个Method对象,存储Method数组中 java.lang.reflect.Method类: 是用来描述成员方法的
  • public Method getMethod(String name, Class... parameterTypes):获取public修饰的指定方法名称,指定参数类型对应的成员方法对象
    参数:

String name: 方法名称
Class... parameterTypes: 必须传递数据类型对应的Class对象,而且是可变参数,可以传递数组,参数列表,不传递(获取空参)

  • 例子

    public class Demo04GetMethod {
        public static void main(String[] args) throws Exception {
            //1.获取Class类型的对象(三种方式,建议使用第三种forName)
            Class<?> c = Class.forName("domain.Person");
            //2.获取所有public修饰的成员方法,包含继承下来的
            Method[] ms = c.getMethods();
            for (Method m : ms) {
                System.out.println(m);
            }
            System.out.println("--------------");
    
            //获取public修饰的名称为toString的没有参数的方法
            Method m1 = c.getMethod("toString");
            System.out.println(m1);
    
            //获取public修饰的名称为setName的参数为String类型的方法
            Method m2 = c.getMethod("setName", String.class);
            System.out.println(m2);
    
            // 获取public修饰的名称为getSum的参数为两个int类型的方法
            //getSum是private修饰的,无法获取,报出异常
            //Method m3 = c.getMethod("getSum", int.class, int.class);
            //System.out.println(m3);
    
            //获取public修饰的名称为my2CharArray的参数为String类型的方法
            Method m4 = c.getMethod("my2CharArray", String.class);
            System.out.println(m4);
    
        }
    }
获取步骤
  1. 获取Class类型的对象(三种方式,建议使用第三种forName)
  2. 用上一步获取的Class对象使用成员方法获取Method对象
利用反射回来的对象调用方法
  • public Object invoke(Object obj,Object... args): 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。(invoke 中文表示调用的意思)

参数:

1.Object obj: 成员方法的执行,必须有对象的支持

2.Object... args: 执行方法时,该方法需要的具体的参数

返回值: java.lang.Object类型

方法执行的结果,被封装成一个Object返回

1.没有返回值的方法: 返回一个null

2.有返回值的方法: Object对象中,封装了具体的结果

public class Demo05Invoke {
    public static void main(String[] args) throws Exception {
        //1.获取Class类型的对象(三种方式,建议使用第三种forName)
        Class<?> c = Class.forName("domain.Person");

        //成员方法的调用,需要对象的支持
        //快捷方式,创建一个对象
        Object obj = c.newInstance();

        //2.获取setName方法对象
        Method setNameMethod = c.getMethod("setName", String.class);
        //3.执行setName方法对象
        Object result = setNameMethod.invoke(obj, "柳岩");
        System.out.println(result);//null
        //System.out.println(obj);

        //2.获取getName方法对象
        Method getNameMethod = c.getMethod("getName");

        //3.执行getName方法对象
        result = getNameMethod.invoke(obj);
        System.out.println(result);

    }
}
知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

发表评论

email
web

全部评论 (暂无评论)

info 还没有任何评论,快来留言吧!