Java基础学习笔记

Java基础

软件开发周期:

  • 客户意向;
  • 软件项目立项,立项报告,立项审批;
  • 需求调研,需求评审;
  • 概要设计,用例图,页面原型设计;
  • 数据库设计,表设计;
  • 详细设计,类设计;
  • 开发编码;
  • 需求变更;
  • 测试;
  • 试运行,修改bug;
  • 正式上线;
  • 运行维护;
  • 项目完成;

image.png

java语言特点:
简单性
编译性
高性能
解释性
面向对象
分布式处理
健壮性
安全性
开源
跨平台

JDK、JRE、JVM的区别
JDK:java开发工具包,是java的核心,包括JRE+编译、运行等命令工具
JRE:java运行环境,是运行java程序所必须的环境的集合,包括JVM和系统类库
JVM:java虚拟机,是java实现跨平台开发的核心、能够运行java语言所开发的程序

标识符:
标识符可以由字母,数字,下划线(_),美元符号($)组成,但不能包含@、%空格等其他特殊字符
不能以数字开头
标识符严格区分大小写

关键字:
image.png

变量:
image.png

基本类型(八种):
image.png
2^(15)=32768
2^(31)=2,147,483,648

image.png
小转大:直接转
大转小:强制类型转换image.png

运算符:
image.png

分支结构:
if、for、while

image.png

//生成100以内的随机数
int random =new Random().nextInt(100);

成员变量,位置在方法里,只能作用于方法内
全局变量,位置在类里方法外,能够作用于类里的所有方法,有初始值,在方法里使用时需要静态申明

方法

方法的重载

是指在一个类中定义多个同名的方法
但要求每个方法具有不同的参数列表(也就是说参数的个数和类型不同)。
程序调用方法时,可以通过传递给它们的不同个数和类型的参数来决定具体使用哪个方法。

数组

数组Array是用于存储多个相同类型数据的集合。想要获取数组中的元素值,可以通过下标来获取,下标从0开始
image.png

数组的长度
数组一旦创建,长度不可变
允许0长度的数组存在

数组遍历的方法:
for循环、Arrays工具类遍历、foreach

        int[] arr = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
        //for循环
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]+"\t");
        }
        //Arrays工具类
        System.out.println(Arrays.toString(arr));
        //foreach
        for (int a:arr) {
            System.out.println(a);
        }

数组的工具类
Arrays
Arrays.toString
把数组里的数据,用逗号连接成一个字符串:【值1,值2】
Arrays.sort
排序
Arrays.copyOf
复制数组并设定长度

面向对象

面向对象是一种编程思想,通过这种思想吧生活中复杂的事情变得简单化,从原来的执行者变成指挥者。
面向对象是基于面向过程而言的。
我们经常说的面向对象的编程实现(OOP,Object Oriented Programming)

三大特征

封装:把相关的数据封装成一个类组件、能够提高代码的安全性
继承:是子类自动共享父类属性和方法,这是类之间的一种关系
多态:增强软件的灵活性和重用性

封装

继承

继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
java继承是使用已存在的类的定义作为基类/父类/超类。新类的定义可以增加新的数据或新的功能,也可以用父类的功能。
但不能选着性的继承父类(超类,基类)。这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。

继承的特点
1、使用extends关键字
2、相当于子类把父类的功能复制了一份
3、java只支持单继承
4、继承可以传递(爷、儿、孙)
5、不能继承父类的私有成员
6、继承多用于功能的修改,子类可以拥有父类的功能的同时,进行功能拓展
7、像is a的关系

方法重写Override
1、继承后,子类就拥有了父类的功能。
2、在子类中可以添加子类特有的功能也可以修改父类的原有功能。
3、子类中方法的申明与父类完全一样时,会发生覆盖/重写操作
4、方法的声明:包括方法的返回值,方法名和参数列表,完全一致
注意:
1、父类中的私有方法不能被重写
2、子类重写父类方法时,修饰符要大于等于父类修饰符的权限。
3、父类中的构造方法不能被子类继承。

多态

多态指同一实体同时具有多种形式
它是面向对象程序设计(oop)的重要特征
主要是指同一个对象,在不同时刻,代表的对象不一样,指 的是对象的多种形态。
好处是可以把不同的子类对象当做父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准
特点:
1、多态的前提是继承
2、要有方法的重写
3、父类引用指向子类对象
4、多态中,编译看左边,运行看右边

向上转型和向下转型

在JAVA中,继承是一个重要的特征,通过extends关键字,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法来加以扩展。
那么在这个过程中就存在着多态的应用。存在着两种转型方式,分别是:向上转型和向下转型。
向上转型:可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。
比如:父类Parent,子类Child
父类的引用指向子类对象:Parent p=new Child();
说明:向上转型时,子类对象当成父类对象,只能调用父类的功能,如果子类重写了父类中声明过的方法,方法体执行的就是子类重过后的功能。但是此时对象是把自己看做是父类类型的,所以其他资源使用的还是父类型的。
比如:花木兰替父从军,大家都把花木兰看做她爸,但是实际从军的是花木兰,而且,花木兰只能做她爸能做的事,在军营里是不可以化妆的。

向下转型(较少):子类的引用的指向子类对象,过程中必须要采取到强制转型。这个是之前向上造型过的子类对象仍然想执行子类的特有功能,所以需要重新恢复成子类对象
Parent p = new Child();//向上转型,此时,p是Parent类型
Child c = (Child)p;//此时,把Parent类型的p转成小类型Child
其实,相当于创建了一个子类对象一样,可以用父类的,也可以用自己的
说明:向下转型时,是为了方便使用子类的特殊方法,也就是说当子类方法做了功能拓展,就可以直接使用子类功能。
比如:花木兰打仗结束,就不需要再看做是她爸了,就可以”对镜贴花黄”了

image.png

java语言最基本单位就是类,类似于类型
类是一类事物的抽象
可以理解为模板或者设计图纸

对象
每个对象具有三个特点:对象的状态,对象标识的和对象的行为
1、对象的状态用来描述对象的基本特征
2、对象的行为用来描述对象的功能
3、对象的标识是指对象在内存中都有唯一的地址值用来和其他对象区分开来
4、类是一类事物的抽象,对象是具体的实现

类和对象的关系
计算机语言是用来描述现实事物的成员属性+成员方法
通过类来描述事物,把事物的属性当做成员变量,把行为当做成员方法

java把内存分成5大区域
1、一般来讲局部变量存在栈中,方法执行完毕内存就被释放
2、对象(new出来)存在堆中,对象不再被使用时,内存才会被释放
3、每个堆内存的元素都有地址值
4、对象中的属性都是有默认值的

java创建对象时,数据在内存中的分布
image.png

构造函数

1、Java构造方法定义

Java中的构造方法是一种特殊的方法,用于初始化对象。Java构造函数在对象创建时被调用。它构造值,即提供对象的数据。与函数名相同,无返回值。
2、作用
一般用来初始化成员属性和方法的,即new对象产生后,就调用了对象的属性和方法。
3、创建Java构造函数的规则
创建函数基本上定义了两个规则。分别如下:
1、构造函数必须与其类名称相同
2、构造函数必须没有显式返回类型

构造方法

构造方法是一种特殊的方法,它是一个与类同名且返回类型为同名的类型的方法。
对象的创建就是通过构造方法来完成,其功能主要是完成对象的创建或者对象的初始化。当类实例化new一个对象时会自动调用构造方法。
构造方法和其他方法一样也可以重载(方法名相同+参数列表不同)

构造代码块
1、在类的内部,方法外部的代码块
2、通常用于抽取构造方法中的共性代码
3、每次调用构造方法钱都会用构造代码块
4、优先于构造方法加载

局部代码块
写在方法里的代码块

ps:构造代码块是在对象创建时就加载,局部代码块则是在方法调用时加载

关键字

作用范围
image.png
private
是一个权限修饰符,用于修饰成员变量和成员函数。被私有化的成员只能在本类中访问

this
代表本类对象的一个引用对象
调用本类的方法、属性

super
不能将值赋给另一个对象变量,它只是一个指示编译器调用超类方法的特殊关键字
通过super关键字可以使用父类的内容
super代表父类的一个引用对象
如果在构造方法中使用必须是第一条语句
super使用时相当于直接创建了一个父类的对象
this是自身的一个对象,代表对象本身

this和super的区别

this:当前对象
this.属性;当前对象的属性
this([参数]);当前对象构造函数,必须写在构造函数内的首行,this.函数名([参数]);当前对象的函数,形参和成员名重名,用this来区分
super:父类对象
super可以理解为是指向自己超(父)类对象,这个超类指的是离自己最近的一个父类。也大致分为3种用法
1、普通的直接引用,与this类似,只不过它是父类对象,可以通过它调用父类成员。
2、子类中的成员变量或方法与父类中的成员变量或方法同名,可以使用super区分。
3、引用构造方法,super(参数):调用父类中的某一个构造方法(应该为构造方法中的第一条语句)
super.属性;父类的属性
super([参数]);父类的构造函数
每一个构造函数内都默认有一个无参的super();

1、super()和this()类似,区别是,super()从子类中调用父类的构造方法,this()在同一类内调用其它构造方法。
2、super()和this()均需放在构造方法内首行。
3、尽管可以用this调用一个构造器,但却不能调用两个。
4、this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
5、从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
6、super在调用时,自动创建一个父类对象

static
1、随着类的加载而加载
2、只加载一次,就会一直存在,直到类消失
3、优先于对象加载
4、被所有对象所共享(一个地方修改值,所有调用它的地方的值都会随之变化)
5、可以直接被类名调用用
静态资源只能调用静态

final
1、被final修饰的类,不能被继承
2、被final修饰的方法,不能被重写
3、被final修饰的变量是个常量

instanceof
result = object instanceof class
左边是对象,右边是类;
当对象是右边类或子类所创建对象时,返回true;否则,返false。

异常

封装错误信息的对象

抽象类

java中可以定义没有方法体的方法,该方法由其子类来具体的实现,该没有方法体的方法我们称之为抽象方法,含有抽象方法的类我们称之为抽象类
抽象类可以理解为是一个只有方法声明没有方法体的特殊类
修饰符 abstract 返回值 方法名(参数列表)
1、通过java关键字abstract实现
2、可以修饰方法或者类
3、抽象类可以没有抽象方法(由子类去实现)
4、如果类中有抽象方法,那该类必须定义为一个抽象类
5、子类继承了抽象类以后,要么还是一个抽象类,要么就吧所有抽象方法都重写
6、多用于多态中
7、抽象类不可以被实例化new
如果类中有抽象方法,这个类必须是一个抽象类
当需要修改抽象父类的原有功能时发生方法重写现象,重写之后就吧父类的方法体修改了,而方法声明必须不能改
当子类继承了一个抽象父类后,子类需要把所有的抽象方法都重写
或者在子类继承一个抽象父类后,子类可以是一个抽象的子类

接口

java里面由于不允许多重继承,所以如果要实现多个类的功能,则可以通过实现多个接口实现,
java接口和java抽象类代表的就是抽象类型,就是我们需要提出的抽象层的具体表现oop面向对象的编程,如果要提高程序的复用率,增加程序的可维护性,可扩展性,就必须是面向接口的编程,正确的使用接口、抽象类这些有用的抽象类型作为java结构层次上的顶层。
1、接口中都是抽象方法
2、通过interface关键字创建接口
3、通过implements让子类来实现
4、可以理解成,接口是一个特殊的抽象类
5、接口突破了java的单继承的局限性
6、接口和类之间可以多实现,接口和接口之间可以多继承
7、接口是对外暴露的规则,是一套开发规范
8、接口提高了程序的功能扩展,降低了耦合性

总结
类和类的关系:继承 extends
–继承的意义:为了提高代码的复用性,减少了代码的编写提高开发效率
–方法重写的意义:在不修改父类源码的前提下,在子类中重写业务,从此使用的就是重写后的功能,要求子类的方法声明和父类一样,只要改方法体。
–有了继承有了重写就产生了多态,多态的意义:为了统一程序的调用标准,标准就是父类
–多态,也就是向上转型/想上转型
–向下转型的意义:相当于想要使用子类的特殊功能,还不如直接创建子类对象简单

类和接口的关系:继承extends、单继承、多继承
–接口的多继承关系,打破了java单继承的局限性

接口和抽象类的区别
–相同点:都是抽象层,都不能实例化
–不同点:
1、抽象类用abstract关键字描述、接口用interface
2、子类和抽象类之间是extends关系,实现类和接口之间是implements关系
3、抽象类中可以有构造方法,接口里不能出现构造方法
4、抽象类里可以有变量,接口里没有变量全部都是静态常量
5、接口里定义常量的语法:public static final String NAME=“XXX”,会为变量自动拼接public static final
6、抽象类里,可以有普通方法 也可以有抽象方法,接口里都是抽象方法
7、抽象类和子类之间是继承关系,而且java中,只支持单继承
8、接口突破了java单继承的局限性,因为接口可以多继承也可以多实现,甚至可以继承的同时多实现
9、接口的复杂用法
多继承
多实现
继承的同时多实现

Java创建对象的过程

java创建对象的过程主要分为一下五个步骤:
(1)类加载检查
Java虚拟机(jvm)在读取一条new指令时候,首先检查能否在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否被加载、解析和初始化。如果没有,则会先执行相应的类加载过程。

(2)内存分配
在通过(1)后,则开始为新生的对象分配内存。该对象所需的内存大小在类加载完成后便可确定,因此为每个对象分配的内存大小是确定的。而分配方式主要有两种,分别为:

1.指针碰撞

应用场合:堆内存规整(通俗的说就是用过的内存被整齐充分的利用,用过的内存放在一边,没有用过的放在另外一边,而中间利用一个分界值指针对这两边的内存进行分界,从而掌握内存分配情况)。

即在开辟内存空间时候,将分界值指针往没用过的内存方向移动向应大小位置即可)。

将堆内存这样划分的代表的GC收集器算法有:Serial,ParNew

2.空闲列表

应用场合;堆内存不规整(虚拟机维护一个可以记录内存块是否可以用的列表来了解内存分配情况)

即在开辟内存空间时候,找到一块足够大的内存块分配给该对象即可,同时更新记录列表。

将堆内存这样划分的代表的GC收集器算法有:CMS

(3)初始化默认值
第(2)步完成后,紧接着,虚拟机需要将分配到的内存空间都进行初始化(即给一些默认值),这将做是为了保证对象实例的字段在Java代码中可以在不赋初值的情况下使用。程序可以访问到这些字段对用数据类型的默认值。

(4)设置对象头
初始化(3)完成后,虚拟机对对象进行一些简单设置,如标记该对象是哪个类的实例,这个对象的hash码,该对象所处的年龄段等等(这些可以理解为对象实例的基本信息)。这些信息被写在对象头中。jvm根据当前的运行状态,会给出不同的设置方式。

(5)执行初始化方法
在(4)完成后,最后执行由开发人员编写的对象的初始化方法,把对象按照开发人员的设计进行初始化,一个对象便创建出来了。

java中什么是字节流?
Java中的字节流有助于执行8位字节的输入和输出操作;它以stream结尾。换句话说,它逐字节处理数据,适用于处理二进制文件等原始数据。字节流操作最常用的类是FileInputStream和FileOutputStream。FileInputStream有助于从源读取,而FileOutputStream有助于写入目标。
java中什么是字符流?
在java中,使用Unicode约定存储字符。字符流自动允许我们逐字符读/写数据,有助于执行16位Unicode的输入和输出;它是以reader和writer结尾的。Java中字符流最常见的类是FileReader和FileWriter。在内部,FileReader使用FileInputStream;同样,FileWrite使用FileOutputStream。
Java中字节流与字符流的区别
1、定义
字节流是一种执行8位字节输入和输出的机制,基本单元为字节;而字符流是Java中执行16位Unicode输入和输出操作的机制,基本单元为Unicode码元。
2、结尾
字节流以stream结尾;而字符流以reader和writer结尾
3、处理方式
字节流是最基本的,采用ASCII编码;它通常用于处理二进制数据,它是按字节来处理的,实际上它可以处理任意类型的数据,但它不支持直接写入或读取Unicode码元。
字符流采用Unicode编码,它是按虚拟机的encode来处理,也就是要进行字符集的转化;它通常处理文本数据,它支持写入及读取Unicode码元。
4、缓冲区
字节流默认不使用缓冲区;字符流使用缓冲区。

image.png

字节流只能读写普通文字文档
字符流可以读写图片

泛型

通常用于结合集合来使用,标志就是<>,通常用来检查集合中元素的类型
作用:可以把报错提前在编译时期,而不是运行时才抛出异常
可以写出通用代码
常用名称:
E-Element(在集合中使用,因为集合中存放的是元素)
T-Type(java类)
K-Key(键)
V-Value(值)
N-Number (数值类型)
?-标识不确定的java类型

集合

以前想要存储多个数据可以用数组,但是数组有缺点:约束了元素的类型,数组长度不能改变,数组遍历的方式单一。
集合可以解决数组的所有问题,元素类型丰富可以是基本类型也可以是引用类型。
集合的长度可变,可以自动扩容和缩容,遍历方式丰富
集合中添加的元素都是引用类型。
![EJKaTeX parse error: Expected '}', got '#' at position 103: …bb5340ad6b8.png#̲averageHue=#ebe…OWSSZZZ[_H95D@{V2DZ3.png&originHeight=583&originWidth=1277&originalType=binary&ratio=1&rotation=0&showTitle=false&size=367646&status=done&style=none&taskId=ub423096f-57ac-4fa8-9f39-5f1bbea0ca5&title=&width=1277)

HashMap

HashMap 的实例有两个参数影响其性能:初始容量 和_加载因子_。容量 是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

进程

正在运行的程序,代表了程序所占用的内存区域
特点:
独立性:进程是系统中独立存在的实体,它可以拥有自己的独立资源,每个进程都拥有自己私有的地址空间。在没有经过进程本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间
动态性:进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。在进程中加入了时间的概念,进程具有自己的生命周期和各种不同的状态,这些概念在程序中都是不具备的
并发性:多个进程可以在单个处理器上并发执行,多个进程之间不会互相影响。

线程

概念:线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个进程可以开启多个线程。多线程扩展了多进程的概念,使得同一个进程可以同时并发处理多个任务
一个程序运行后至少一个进程,一个进程里包含多个线程
如果一个进程只有一个线程,这种程序被称为单线程
如果一个进程中有多条执行路径被称为多线程程序

线程状态:
1、新建状态,是指线程刚刚产生,new
2、可运行状态,等待被CPU调度,等CPU调度时才开始正式干活,但是CPU的执行效率非常快
3、运行状态,是指已经被CPU调用了开始干活了
4、理想状态下,干完活就变成了终止状态
5、如果运行时出现了其他现象,导致没有成功的把任务完成,线程就会进入阻塞状态

并发

是指同一时刻,多个程序在抢占共享资源,同时抢占CPU来执行程序

并行

是指同一时刻,有多个CPU在干活,但是一个CPU只干一件事

解决多线程的方法
概念:
异步:多个线程同时对共享资源进行操作,在操作数据时,互相之间不需要等待,提高执行效率,降低资源的安全性
同步:多个线程在操作共享资源时,只有一个线程在操作,另外的线程必须等待,
加同步锁:把那些有多线程并发数据安全隐患的代码用同步包起来,同一时刻只让一个线程执行,其他线程处于等待状态,虽然降低了程序的执行效率和性能,但是提高了共享资源的安全性
锁可以存在的位置:位置要根据业务决定找到合适的位置,如果锁的范围太大会造成资源浪费,因为锁起来的部分执行效率非常低,如果锁的范围太小,可能根本就没有解决安全问题,数据还是存在隐患
锁的对象:多个线程间要使用同一把锁,才能保证数据的安全。不能每个线程使用自己的锁,相当于自己的线程用了自己的锁,但是并没有真正的锁住共享资源,仍然有数据安全隐患
同步锁synchronized可以修饰代码块也可以修饰方法,如果方法里都是同步代码,可以吧synchronized直接写上方法

synchronized
synchronized(对象){
需要同步的代码

1、前提1,同步需要两个或者两个以上的线程
2、前提2,多个线程间必须使用同一个锁
3、同步的缺点是会降低程序的执行效率,为了保证线程安全,必须牺牲性能
4、可以修饰方法称为同步方法,使用的锁对象是this
5、可以修饰代码块称为同步代码块,锁对象可以任意

反射

反射是java程序开发语言的特征之一,它允许运行中的java程序对自身进行检查。反射十分强大,它可以直接操作程序的私有属性。它可以在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器),并且可以操作类的字段、方法、构造器等部分

暴力反射

package cn.xiong.reflection;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class Reflect_Person {
    public static void main(String[] args) {

    }
    @Test
    public void method1(){
        Class<Person> personClass = Person.class;
        Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
        for (Constructor dc:declaredConstructors) {
            System.out.println(dc);
        }
    }
    @Test
    public void method2() throws Exception {
        Class<Person> personClass = Person.class;

        Method declaredMethod = personClass.getDeclaredMethod("show", int[].class);
        Person person = personClass.newInstance();
        declaredMethod.setAccessible(true);//设置私有可见
        declaredMethod.invoke(person,new int[]{1,2,3});//(n,m)n代表所要执行的方法,m代表方法所需要的参数

    }
}

内部类

如果一个类存在的意义就是为指定的另一个类,可以把这个类放入另一个类的内部。就是把类定义在类的内部的情况就可以形成内部类的形式
a类中又定义了b类,b类就是内部类。b类可以当做a类的一个成员看待

特点
内部类可以访问外部类的资源,包括私有
外部类要访问内部类的成员,必须创建对象
在成员位置的内部类是成员内部类
在局部位置的内部类是局部内部类

package cn.xiong.inner;
//这个类用来测试内部类
public class Test01_Inner {
    public static void main(String[] args) {
        outer outer = new outer();
        outer.out();
        cn.xiong.inner.outer.Inner inner = new outer().new Inner();
        inner.in();
    }
}
class outer{
    int age;
    String name = "zhangsan";
    public void out(){
        System.out.println("waibulei  out()");

    }
    class Inner{
        int innernum=20;
        public void in(){
            System.out.println("neibulei  in()");

        }
    }
}

package cn.xiong.inner;
//测试内部类的使用
public class Test02_Inner {
    public static void main(String[] args) {
        outer2 outer2 = new outer2();
        outer2.showin();
    }
}
class outer2{

    public  void showin(){
        new inner02().in();
    }
   private class inner02{
        public void in(){
            System.out.println("内部类");
        }
    }
}
package cn.xiong.inner;
//这个类用来测试内部类
public class Test03_Inner {
    public static void main(String[] args) {
        Outer3.Inner3 inner3 = new Outer3. Inner3();
        inner3.Inner();
        Outer3.Inner3.Inner2();//链式编程
    }
}
class Outer3{

    static class Inner3{
        static public void Inner2(){
            System.out.println("内部类");
        }
        public void Inner(){
            System.out.println("内部类");
        }

    }
}

套接字Socket

套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议栈进行交互的接口
抽象的端口:0-65535 其中0-1024被系统占用
服务器端ServerSocket
创建对象:ServerSocket(int port)创建绑定到特定端口的服务器套接字。
常用方法:Socket accept()侦听并接受到此套接字的连接
void close()关闭此套接字
客户端Socket
创建对象:Socket(String host, int port)创建一个流套接字并将其连接到主机上的指定端口号
常用方法:void close()关闭此套接字
InputStream.getInputStream(); 返回此套接字的输入流
OutputStream .getOutputStream(); 返回此套接字的输出流
服务器端多线程改造
accept()只能接受一个连接的请求,第二个请求没有机会,需求让accept()循环执行
read()死等数据,当客户端连接服务器成功后,第一时间来分配话务员

回声案例
需求:接受客户端输入的一行数据,服务器再把数据回声给客户端
角色
服务器:让accept()方法循环起来可以接受多个连接+给每个客户端分配话务员
话务员:读取客户端的数据,回声给客户端数据
客户端:一直给服务器发送数据,并接受服务器回声回来的数据in
服务器端:

package cn.xiong.manysocket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

//这个类用来完成回声案例服务端
/*
1、让accept循环起来
2、给每个客户端分配话务员
 */
public class Server2 {
    //启动服务器-接受客户端连接-分配话务员
    public void service(){
        new Thread(){//匿名类
            @Override
            public void run() {
                try {
                    ServerSocket serverSocket = new ServerSocket(9000);
                    System.out.println("服务器已启动.....");
                    while (true){
                        Socket socket = serverSocket.accept();
                        System.out.println("客户端连接成功....");
                        HuaWuThread t=new HuaWuThread(socket);
                        t.start();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }


            }
        }.start();//启动线程
    }
    //内部类只被server2调用
    class HuaWuThread extends Thread{

        Socket s;
        public HuaWuThread(Socket socket){
                this.s=socket;
        }

        @Override
        public void run() {
            try{
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(s.getInputStream()));
                PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));

                String line ;
                while ((line=bufferedReader.readLine())!=null){
                    System.out.println("客户端发来的数据是:"+line);
                    printWriter.println(line);
                    printWriter.flush();//把数据刷出去
                }

            }catch(Exception e){
                e.printStackTrace();
            }
        }


    }

    public static void main(String[] args) {
        Server2 server2 = new Server2();
        server2.service();
    }
}


客户端:

package cn.xiong.manysocket;

import java.io.*;
import java.net.Socket;
import java.util.Scanner;

//这个类用来完成回声案例 客户端
public class Client2 {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1", 9000);

            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));

            while (true){
                String input = new Scanner(System.in).nextLine();
                printWriter.println(input);//一行一行写出去
                printWriter.flush();//把数据刷出去

                String line = bufferedReader.readLine();
                System.out.println("服务器的回声数据是:"+line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

设计规则
1、将派生类所共有的属性和行为,抽象到超类中————抽共性
2、若派生类的行为/代码都一样,设计为普通方法
3、若派生类的行为/代码都不一样,设计为抽象方法

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值