20.设计原则
设计原则:
开闭原则:
对现有代码修改关闭,对扩展代码开放
举例:
项目开发完毕,进行更新,不能够修改现有代码,在现有代码的基础上提供扩展!
接口分离原则
一个接口中定义一个功能,接口和接口之间独立的,不能相互影响
实际开发中:
某个接口中,可能将相关的功能都定义在这一个接口中
按模块划分:
用户模块 UserDao 接口
login()/register()/logout()/checkUserName()
商品模块
ProductDao 接口
Product findById(Integer id) ;
List<Product> findAll() ;
void update(Product product);
订单模块
OrderDao 接口
List<Order> findPage(int pageSize,int currentPage);
里氏替换原则:任何父类出现的地方都可以子类替代!
class Father{
public void show(){
// ...
Class<Son> clazz = Son.class ;
//反射方式---->字节码文件对象就调用method----->将所有的成员方法---->Method
}
}
class Son extends Father{
public void method(){
}
}
23种设计模式都需要遵循 原则"低耦合,高内聚"
设计模式是一种思想,前人总结出来,不是技术!
创建型:对象的创建 (使用最多)
结构型:整个结构的组成
代理模式
静态代理
代理角色
真实角色
行为型:具备功能性的
创建型设计模式:
简单工厂:----称为 静态工厂方法模式
优点:利用多态创建子类对象,能够灵活去创建对象(提供的静态功能)
弊端:代码量大,一旦有新的类型增加,工厂类的静态功能就需要改动...
1.工厂模式
工厂方法模式:
1)抽象类:Animal 动物类 (基类)
2)提供一些子类,完成方法重写:eat(){} sleep(){}
3)提供一个接口 :
Factory
public Animal createAnimal() ;
DogFactory /CatFactory具体的子实现类实现对象的创建
优点:具体的动物创建,交给类工厂类来实现 (面向接口编程),便于功能维护(代码维护)
弊端:代码量非常大
如果有新的类中增加,那么还必须提供对应具体的工厂类创建当前类实例!
public abstract class Animal {
public abstract void eat() ;
public abstract void sleep() ;
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void sleep() {
System.out.println("猫趴着睡觉...");
}
}public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头...");
}
@Override
public void sleep() {
System.out.println("狗躺着睡觉...");
}
}
public interface Factory {
public Animal createAnimal() ;}
public class CatFactory implements Factory{
@Override public Animal createAnimal() {
return new Cat(); }
}
public class DogFactory implements Factory{
@Override
public Animal createAnimal() {
return new Dog();
}
}public class FactoryPattern {
public static void main(String[] args) {
Animal a = new Dog() ;
a.eat();
a.sleep();
System.out.println("-------------------------------");
a = new Cat() ;
a.eat();
a.sleep();
System.out.println("-------------------------------------");
Factory factory = new DogFactory() ;
Animal animal = factory.createAnimal();
animal.eat();
animal.sleep();
System.out.println("---------------------------------------");
factory = new CatFactory() ;
Animal a2 = factory.createAnimal();
a2.eat();
a2.sleep();
}
}
2.单例模式
单例模式: 始终在内存中创建一个实例分为两种
饿汉式:永远不会出现的单例模式(最简单的一种单例)
懒汉式:可能出现问题的一种单例模式
1)饿汉式
饿汉式
1)构造方法私有:保证外界不能直接创建当前类对象
2)在当前类的成员位置:创建当前类实例
3)提供一个静态的功能,返回值就是当前类本身(需要当前类的实例)
public class Student {
private static Student s = new Student() ;
private Student(){}
public static Student getStudentInstance(){
return s;
}
}
public class Single_Pattern_01 {
public static void main(String[] args) {
Student s1 = Student.getStudentInstance();
Student s2 = Student.getStudentInstance();
Student s3 = Student.getStudentInstance();
Student s4 = Student.getStudentInstance();
System.out.println(s1==s2);
System.out.println(s1==s3);
System.out.println(s1==s4);
}
}
2)懒汉式
懒汉式:可能出现问题的一种单例模式
1)构造方法私有化
2)在当前成员变量的位置声明变量:数据类型就是当期类 (私有的,静态的)
3)提供静态功能,返回值还是当前类本身,
判断如果当前没有给当前类型变量为null,直接new 当期类的实例
如果不为null,就返回当前类的变量!
延迟加载或者懒加载----出现安全问题 面试中,问的最多就是懒汉式----->如何解决线程安全问题: 想到同步方法解决
public class Worker {
private static Worker w;
private Worker() {}
public synchronized static Worker getWorkerIntance(){
if(w == null){
w = new Worker() ;
return w;
}
return w ;
}
}
public class Single_pattern_02 {
public static void main(String[] args) {
Worker w1 = Worker.getWorkerIntance();
Worker w2 = Worker.getWorkerIntance();
System.out.println(w1==w2);
Worker w3 = Worker.getWorkerIntance();
System.out.println(w1==w3);
}
}
3.Runtime类
Runtime:当前获取的当前本地运行环境的实例
public int availableProcessors():获取本地计算机的处理器的数量
public Process exec(String command):开启某个软件的进程(参数为字符串命令)
exec("shutdown -s"):立即关机
exec("shutdown -s -t 300"):延时关机
exec("shutdown -a"):取消关机
public class RuntimeDemo {
public static void main(String[] args) throws IOException {
Runtime runtime = Runtime.getRuntime();
System.out.println(runtime.availableProcessors());
Process notepad = runtime.exec("notepad");
System.out.println(runtime.exec("QQ"));
System.out.println(runtime.exec("shutdown -s -t 300"));
System.out.println(runtime.exec("shutdown -a"));
}
}
public class DiGuiDemo {
public static void main(String[] args) {
System.out.println("5的阶乘是:"+jieCheng(5));
}
private static int jieCheng(int i) {
if(i==1){
return 1 ;
}else{
return i * jieCheng(i-1) ;
}
}
}
public class DiGuiTest {
public static void main(String[] args) {
File srcFloder = new File("d://demo") ;
deleteFloder(srcFloder) ;
}
public static void deleteFloder(File srcFloder) {
File[] fileArray = srcFloder.listFiles();
if(fileArray!=null){
for(File file:fileArray){
if(file.isDirectory()){
deleteFloder(file) ;
}else{
if(file.getName().endsWith(".java")){
System.out.println(file.getName()+"------------"+file.delete());
}
}
}
System.out.println(srcFloder.getName()+"----"+srcFloder.delete());
}
}
}
4.代理模式
1)静态代理
第二种实现方式:
静态代理
特点:真实角色和代理角色必须实现同一个接口
真实角色:专注于自己的功能
代理角色:完成对真实角色功能的"增强"
interface Mary{
void mary() ;
}
class You implements Mary{
@Override
public void mary() {
System.out.println("结婚了,很开心...");
}
}
class WeddingCompany implements Mary{
private You you ;
public WeddingCompany(You you){
this.you = you ;
}
@Override
public void mary() {
System.out.println("给你布置婚礼现场...");
you.mary();
System.out.println("婚礼线程布置完毕,吃席...");
}
}
public class ThreadDemo {
public static void main(String[] args) {
You mary = new You() ;
mary.mary();
System.out.println("----------------------");
You you2 = new You() ;
WeddingCompany wc = new WeddingCompany(you2) ;
wc.mary();
}
}
2)动态代理
动态代理
jdk动态代理
cglib动态代理-----导入cglib第三方jar包
1.动态代理核心思想:
再程序执行过程中通过一些特殊的方式产生代理
2.代理角色和真实角色
代理角色完成真实角色的一些额外功能,
真实角色专注于完成自己的事情!
3.jdk动态代理:
前提必须有一个接口 比如 :UserDao
jdk提供的
java.lang.reflect.Proxy:提供了创建动态代理类和实例的静态方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException
参数1:当前针对该接口的类加载器
参数2:代理类实现的接口列表的字节码文件对象
参数3:基于代理的处理程序 接口
自定义一类来实现 代理角色的产生 (InvocationHandler:基于代理的处理接口)
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy 代理实例
method 调用基于接口的代理方法 method底层调用方法 invoke(当前类的实例,实际参数 args)
args 当前传递的实际参数
返回代理角色
throws Throwable 代理过程中可能产生代理异常
目前接口:
UserDao接口 -------> 产生代理角色完成 "权限校验" "日志记录
public interface UserDao {
void add() ;
void update() ;
void delete() ;
void findAll() ;
}
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("添加用户");
}
@Override
public void update() {
System.out.println("修改用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void findAll() {
System.out.println("查询所有用户");
}
}
public class MyInvocationHandler implements InvocationHandler {
private Object target ;
public MyInvocationHandler(Object target){
this.target = target ;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("权限校验");
Object returnObj = method.invoke(target, args);
System.out.println("日志记录");
return returnObj;
}
}
public class UserTest {
public static void main(String[] args) {
UserDao ud = new UserDaoImpl() ;
ud.add();
ud.delete();
ud.update();
ud.findAll();
System.out.println("-------------------------------------");
MyInvocationHandler invocationHandler = new MyInvocationHandler(ud) ;
UserDao proxyClass = (UserDao) Proxy.newProxyInstance(UserDao.class.getClassLoader(),
new Class[]{UserDao.class}, invocationHandler);
proxyClass.add();
proxyClass.delete();
proxyClass.update();
proxyClass.findAll();
}
}
动态代理模板
public class MyInvocationHandler implements InvocationHandler {
private Object target ;
public MyInvocationHandler(Object target) {
this.target = target ;
}
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this) ;
}
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {
System.out.println("方法:" + method.getName()) ;
Object result = method.invoke(target, args) ;
return result;
}
}
public interface UserDao {
void add() ;
void update() ;
void delete() ;
void findAll() ;
}
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("添加用户");
}
@Override
public void update() {
System.out.println("修改用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void findAll() {
System.out.println("查询所有用户");
}
}
public class MyInvocationHandler implements InvocationHandler {
private Object target ;
public MyInvocationHandler(Object target) {
this.target = target ;
}
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this) ;
}
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {
System.out.println("方法:" + method.getName()) ;
Object result = method.invoke(target, args) ;
return result;
}
}
public class Test {
public static void main(String[] args) {
UserDaoImpl useDan = new UserDaoImpl();
MyInvocationHandler mih = new MyInvocationHandler(useDan);
UserDao proxy = (UserDao) mih.getProxy();
proxy.add();
proxy.delete();
proxy.findAll();
proxy.update();
}
}
21.递归
1.方法递归:方法调用方法本身的一种现象,并非是方法嵌套方法
前提条件
1)必须有一个成员方法
2)必须有方法递归的出口条件(结束条件),如果没有出口条件,就是死递归...
3)还存在一定的规律
注意事项:构造方法不存在递归
伪代码:
public void show(int n){ //50 调用
if(n<0){
System.out.println(n) ;
}
n -- ;//49
show(n) ;
}
Math.max(Math.max(10,30),50) ; //× 嵌套
需求:使用递归方式去删除D盘某个demo文件夹中有很多个目录,
每个目录中可能还有目录,删除这些所有目录中的带.java文件的文件!
分析:
1)描述下D盘下demo文件夹 File srcFile = new File("d://demo")
2)调用递归删除方法
//递归删除多级目录中的java文件
public void deleteSrcFile(File srcFile){
//获取srcFile的所有的文件夹以及文件的File数组
//非空判断
//判断如果是文件夹
回到2)继续调用递归删除
则,是文件
判断是否以.java文件
最终删除文件即可!
public class DiGuiTest {
public static void main(String[] args) {
File srcFloder = new File("d://demo") ;
deleteFloder(srcFloder) ;
}
public static void deleteFloder(File srcFloder) {
File[] fileArray = srcFloder.listFiles();
if(fileArray!=null){
for(File file:fileArray){
if(file.isDirectory()){
deleteFloder(file) ;
}else{
if(file.getName().endsWith(".java")){
System.out.println(file.getName()+"------------"+file.delete());
}
}
}
System.out.println(srcFloder.getName()+"----"+srcFloder.delete());
}
}
}
有一对兔子,从出生后第三个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,
假如兔子都不死,问第二十个月的兔子对数为多少?(递归方式实现:找规律)
不死神兔
月数 兔子对数
第一个月 1
第二个月 1
第三个月 2
第四个月 3
第五个月 5
第六个月 8
第七个月 13
...
规律
1)第一个和第二个月:兔子对数都是1
2) 从第三个月开始:兔子对数等于两个月兔子对数之后
a,b分别相邻两个月兔子的对数
第一个月: 1 a
第二个月: 1 b
第三个月: 2 a
第四个月: 3 b
第五个月: 5 a
第六个月: 8 b
方式1)可以使用数组完成
方式2)递归思想完成
递归:
1)定义一个方法
2)得有结束条件(出口条件)
3)必须有规律
定义变量n:来表示月份数(1,2,3...20)
public static int getRabit(int n){
if(n==1 ||n==2){
return 1 ;
} else{
//n=3
//getRabit(1) +getRabit(2)
return getRabit(n-2)+getRabit(n-1) ;
}
}
public class Test4 {
public static void main(String[] args) {
int[] arr = new int[20] ;
arr[0] = 1 ;
arr[1] = 1 ;
for(int x = 2 ; x < arr.length ;x ++){
arr[x] = arr[x-2] + arr[x-1] ;
}
System.out.println("第二十月兔子的对数是:"+arr[19]);
System.out.println("-----------------------------------------------");
System.out.println("第二十个月兔子的对数是:"+getRabit(20));
}
public static int getRabit(int n){
if(n==1||n==2){
return 1 ;
}else{
return getRabit(n-2)+getRabit(n-1) ;
}
}
}
22.IO流
1.File
File 文件和目录(文件夹)路径名的抽象表示。
1.构造方法
1)File(String pathname) :参数就是指定的路径/如果没有指定路径(默认是在当前项目下)
通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
2)File(File parent, String child)
从父抽象路径名和子路径名字符串创建新的 File实例。
3)File(String parent, String child):参数1:父目录地址 参数2:具体的子文件地址
2.成员方法:
创建/删除/重名
1)public boolean createNewFile() throws IOException :表示创建文件 :如果不存在,则创建
2)public boolean mkdir():创建文件夹,如果不存在,则创建;否则就返回false
3)public boolean mkdirs():创建多个文件,如果父目录不存在,则创建
4)public boolean delete():删除文件或者文件夹(如果删除文件夹,文件夹必须为空目录)
5)public boolean renameTo(File dest):重命名
参数传递的修改的File对象
public class FileDemo {
public static void main(String[] args) throws IOException {
File file = new File("D:\\EE_2106\\day25\\code\\a.txt");
File file2 = new File("aaa.txt");
File file3 = new File("D:\\EE_2106\\day25\\code\\demo") ;
File file4 = new File("aaa\\bbb\\ccc\\ddd") ;
System.out.println(file.createNewFile());
System.out.println(file2.createNewFile());
System.out.println(file3.mkdir());
System.out.println(file4.mkdirs());
System.out.println(file3.delete());
System.out.println(file.delete());
System.out.println("------------------------");
File srcFile = new File("D:\\EE_2106\\day25\\code\\mv.jpg") ;
File destFile = new File("高圆圆.jpg") ;
System.out.println(srcFile.renameTo(destFile)) ;
}
}
3.判断功能
1)public boolean canRead()是否可读
2)public boolean canWrite()是否可写
3)public boolean exists():是否存在
4)public boolean isFile():是否是文件
5)public boolean isDirectory():是否是文件夹
6)public boolean isHidden():是否隐藏
4.高级获取功能:
1)public long length()
2)public String getName():获取抽象路径 名所表示的文件或者目录的名称
3)public File[] listFiles():获取某个目录下的所有的文件以及文件夹的File数组
4)public String[] list():获取某个抽象路径名所表示的文件以及目录的字符串数组
public class FileDemo2 {
public static void main(String[] args) {
File file = new File("aaa.txt") ;
System.out.println(file.canRead());
System.out.println(file.canWrite());
System.out.println(file.exists());
System.out.println(file.isDirectory());
System.out.println(file.isFile());
System.out.println(file.isHidden());
System.out.println(file.length());
System.out.println(file.getName());
System.out.println("------------------------");
File file2 = new File("d://") ;
File[] fileArray = file2.listFiles();
if(fileArray!=null){
for(File f :fileArray){
System.out.println(f.getName());
}
}
System.out.println("----------------------------------");
String[] strArray = file2.list();
if(strArray!=null){
for(String s:strArray){
System.out.println(s);
}
}
}
}
需求2:
获取D盘下所有的以.jpg结尾的文件
分析:
1)描述下D盘
2) public File[] listFiles():获取D盘下的所有的文件以及文件夹的File数组
2.1)对获取到的数组进行非判断
如果不为null,再去判断
2.2)判断File是一个文件
2.3)判断:文件必须以.jpg结尾
String类 endsWith(".jpg")
提供了另一个重载功能:
public File[] listFiles(FilenameFilter filter)
String[] list(FilenameFilter filter)
参数为:文件名称过滤器FilenameFilter:接口
成员方法:
boolean accept(File dir,String name):测试指定文件是否包含在文件列表中
返回如果true,将文件添加到文件列表中
1) 描述下D盘
2) public File[] listFiles(FilenameFilter filenamefilter):
获取D盘下的File数组的时候,就已经指定文件进行过滤...
public class FileTest {
public static void main(String[] args) {
File file = new File("D://") ;
File[] fileArray = file.listFiles();
if(fileArray!=null){
for(File f:fileArray){
if(f.isFile()){
if(f.getName().endsWith(".jpg")){
System.out.println(f.getName());
}
}
}
}
System.out.println("-------------------------------------------------------");
File srcFile = new File("D://") ;
File[] files = srcFile.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
File file = new File(dir, name);
return file.isFile() && file.getName().endsWith(".jpg");
}
});
if(files!=null){
for(File f :files){
System.out.println(f.getName());
}
}
}
}
2.IO流的分类
IO流的分类:
按流的方向:
输入和输出流
按类型分:
字节和字符流:字节先出现,后面在有字符流
再次流的方向划分
字节输入流:InputStream:表示输入字节流的所有类的超类(父类)
字节输出流:OutputStream:表示字节输出流的所有类的超类
字符输入流:Reader表示输入字符流的抽象类
字符输出流:Writer表示输出字符流的抽象类
字节/字符流都很多子类
XXXInputStream
XXXOutputStream
XXXReader
XXXWriter
3.字节流
1)OutputStream
字节输出流:OutputStream抽象类 子类进行实例化FileOutputStream:将指定的内容写到文件中 实现步骤: 1)创建文件输出流对象 :FileOutputStream(String name) :推荐:可以指定参数地址 FileOutputStream(File file) 写入文件末尾处构造函数:public FileOutputStream(File file,boolean append)throws FileNotFoundException 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。 2)写数据 public void write(int b) throws IOException 写一个字节 public void write(byte[] bytes) throws IOException 写一个字节数组 public void write(byte[] bytes,int off,int len) throws IOException:写一部分字节数组 3)关闭资源
public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("my.txt") ;
for(int x = 0 ; x < 10 ; x ++){
fos.write(("hello world").getBytes());
fos.write("\r\n".getBytes());
}
fos.close();
}
}
public class FileOutputStreamDemo2 {
public static void main(String[] args) {
method2() ;
}
private static void method2() {
FileOutputStream fos = null ;
try {
fos = new FileOutputStream("fos2.txt") ;
fos.write("hello,我来了".getBytes());
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void method1() {
FileOutputStream fos = null ;
try {
fos = new FileOutputStream("fos.txt") ;
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
fos.write("hello,IO".getBytes()) ;
} catch (IOException e) {
e.printStackTrace();
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2)InputStream
字节输入流:InputStream 子类:FileInputStream实现步骤: 需要读取当前项目下的fis.txt文件 1)创建文件字节输入流对象,指向 fis.txt public FileInputStream(String name) throws FileNotFoundException 2)读内容 public int read(byte[] bytes) throws IOException一次读取一个字节数组 ,返回值值的是每次读取的实际字节数 read():一次读取一个字节 3)释放资源 读取文件的时候,一次读取一个字节,存在中文乱码, 在最终输出的结果 (char)by (场景:将某一个文件内容打印在控制台上了) 注意: "abc" 英文 读一个字节 a--->97 b --98 针对中文字符: 现在idea环境: 编码格式:utf-8格式: 一个中文对应三个字节 ,和前面的英文拼接出现问题,只要中文都会乱码 才出现了字符流(加入编码和解码的格式)
public class FileInputStreamDemo {
public static void main(String[] args) {
FileInputStream fis = null ;
try {
fis = new FileInputStream("DiGuiTest.java") ;
int by = 0 ;
while((by=fis.read())!=-1) {
System.out.print((char)by);
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public class FileInputStreamDemo2 {
public static void main(String[] args) {
FileInputStream fis = null ;
try {
fis = new FileInputStream("fis2.txt") ;
byte[] buffer = new byte[1024] ;
int len = 0 ;
while((len=fis.read(buffer))!=-1){
System.out.println(new String(buffer,0,len)) ;
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
读写复制操作:一次读取一个字节的方式 一次读取一个字节数组需求: 将当前项目下的DiGuiTest.java 的内容 复制到D盘下的Copy.java文件中分析: 源文件: 当前项目下 "DiGuiTest.java" 封装源文件:FileInputStraem(String pathname) 一次读取一个字节 目的地文件: D://Copy.java 封装目的地文件:FileOutputStream(String pathname) 一次写一个字节
public class CopyFileDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis() ;
method2("DiGuiTest.java","D://Copy.java") ;
long end = System.currentTimeMillis() ;
System.out.println("共耗时:"+(end-start)+"毫秒");
}
private static void method2(String srcFile, String destFile) {
FileInputStream fis = null ;
FileOutputStream fos = null ;
try {
fis = new FileInputStream(srcFile) ;
fos = new FileOutputStream(destFile) ;
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fos.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void method(String srcFile, String destFile) {
FileInputStream fis = null ;
FileOutputStream fos = null ;
try {
fis = new FileInputStream(srcFile) ;
fos = new FileOutputStream(destFile) ;
int by = 0 ;
while((by=fis.read())!=-1){
fos.write(by);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fos.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.缓冲字节流
1)BufferedInputStream
字节缓冲输入流构造方法
BufferedInputStream(InputStream in) :默认缓冲区大写 (足够大了) 提供一个指定的缓冲区大小 BufferedInputStream(InputStream in, int size)
public class BufferedInputStreamDemo {
public static void main(String[] args) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bos.txt")) ;
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=bis.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
}
}
2)BufferedInputStream
缓冲流的特点:提供缓冲区大写:1024的8倍 还是通过底层流提高读速度(FileInputStream)构造方法:
BufferedInputStream
BufferedOutputStream(OutputStream out) 推荐使用这个:默认缓冲区大小 足够大了 8kb
创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
BufferedOutputStream(OutputStream out, int size)
public class BufferedOutputStreamDemo {
public static void main(String[] args) throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt")) ;
bos.write("hello.bufferedOutputStream".getBytes());
bos.close();
}
}
复制对比
读取D://a.mp4
将这个文件内容复制到 当前项目下的copy.mp4中
基本的字节流一次读取一字节
共耗时89021毫秒
基本的字节流一次读取一字节数组
共耗时116毫秒
字节缓冲流一次读取一个字节
共耗时348毫秒
字节缓冲流一次读取一个字节数组
共耗时47毫秒
public class CopyMp4 {
public static void main(String[] args) {
long start = System.currentTimeMillis() ;
copyMp4_4("D://a.mp4","copy.mp4") ;
long end = System.currentTimeMillis() ;
System.out.println("共耗时"+(end-start)+"毫秒");
}
private static void copyMp4_4(String srcFile, String destFile) {
BufferedInputStream bis = null ;
BufferedOutputStream bos = null ;
try {
bis = new BufferedInputStream(new FileInputStream(srcFile)) ;
bos = new BufferedOutputStream(new FileOutputStream(destFile)) ;
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
bos.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void copyMp4_3(String srcFile, String destFile) {
BufferedInputStream bis = null ;
BufferedOutputStream bos = null ;
try {
bis = new BufferedInputStream(new FileInputStream(srcFile)) ;
bos = new BufferedOutputStream(new FileOutputStream(destFile)) ;
int by = 0 ;
while((by=bis.read())!=-1){
bos.write(by);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
bos.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void copyMp4_2(String srcFile,String destFile){
FileInputStream fis = null ;
FileOutputStream fos = null ;
try {
fis = new FileInputStream(srcFile) ;
fos = new FileOutputStream(destFile) ;
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
fos.flush();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fos.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void copyMp4(String srcFile, String destFile) {
FileInputStream fis = null ;
FileOutputStream fos = null ;
try {
fis = new FileInputStream(srcFile) ;
fos = new FileOutputStream(destFile) ;
int by = 0 ;
while((by=fis.read())!=-1){
fos.write(by);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fos.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.字符流
1)Writer–OutputStreamWriter
Writer:抽象类 (字符流的出现是在字节流的后面,可以解决中文乱码问题)
提供子类:字符转换输出流: 字节输出流通向字符输出流的桥梁!
构造方法
OutputStreamWriter(OutputStream out) :使用平台默认编码集写入数据
OutputStreamWriter(OutputStream out, String charsetName) :使用指定的字符集进行编码 写入数据 write write(String str)
write(int ch):写入字符: 字符--->对应的ASCII码表
write(char[] ch)
write(char[] ch,int off,int len)
write(String str,int off,int len)
public class WriterDemo {
public static void main(String[] args) throws Exception {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt")) ;
osw.write("hello,字符流我来了");
osw.write(97);
char[] chs = {'A','B','C','D','E'} ;
osw.write(chs);
osw.write(chs,2,2);
osw.flush();
osw.close();
}
}
2)Reader–InputStreamReader
Reader:抽象类 具体的子类:字符转换输入流 InputStreamReader构造方法 InputStreamReader(InputStream in) :使用平台默认解码集进行读 InputStreamReader(InputStream in,String charset) :使用指定的解码集进行读
public class ReaderDemo {
public static void main(String[] args) throws Exception {
InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"));
char[] chs = new char[1024] ;
int len = 0 ;
while((len=isr.read(chs))!=-1){
System.out.println(new String(chs,0,len));
}
isr.close();
}
}
3)便捷类
Reader/Writer子类:转换流
InputStreamReader(InputStream in)
OutputStreamWriter(OutputStream out)
他们不能直接去操作文件,jdk提供了这两种类型的便捷类,可以直接操作文件
FileReader(File file)
FileReader(String pathname)
FileWriter(File file)
FileWriter(String filename)
public FileWriter(File file,boolean append)throws IOException
根据给定的 File 对象构造一个 FileWriter 对象。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。 这两个类:使用的平台的默认编码和解码 (utf-8)
需求: 当前项目下的ReaderDemo.java 复制到 D://Demo.java 针对文本文件:优先采用字符流
6.字符缓冲流
1)BufferedReader
字符缓冲输入流: BufferedReader ---- 键盘录入数据 Scanner(InputSteram in)
String nextLine()
BufferedReader(Reader in)
Reader
InputStreamReader(InputStream in):转换流
如果直接进行读的操作(直接操作文件)FileReader(String pathName)
创建使用默认大小的输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int size) :指定缓冲区大小特有功能:
public String readLine() :一次读取一行内容
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
BufferedReader br2 = new BufferedReader(new FileReader("bw.txt")) ;
String line2 = null ;
while((line2=br2.readLine())!=null){
System.out.println(line2);
}
}
}
2)BufferedWriter
BufferedWriter:字符缓冲输出流
BufferedWriter(Writer out) :创建默认的缓冲区大小: 默认大小:defaultcharbuffersize:8192(默认值足够大) BufferedWriter(Writer out, int sz) :指定的大小
public void newLine() throws IOException:写入行的分隔符号特有功能:
利用BufferedReader的readLine()读取一行
利用BufferedWriter写一行,然后换行 public void newLine() throws IOException:
public class BufferedWriterDemo {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
bw.write("hello");
bw.newLine();
bw.write("world");
bw.newLine();
bw.write("javaEE");
bw.newLine();
bw.flush();
bw.close();
}
}
3)Copy
BufferedReaer/BufferedWriter :读写复制操作
一次读取一个字符
一次读取一个字符数组特有功能:
利用BufferedReader的readLine()读取一行
利用BufferedWriter写一行,然后换行 将当前项目下的
ReaderDemo.java 复制到当前项目下:copy.java
一个文本文件读写复制:
阻塞流 (传统的IO流)
当一个线程如果操作的是读的动作, read(byte[] byte/char[] ..)/readLine():都属于阻塞式方法
另一个线程如果操作的是写的动作,读的线程如果开始读,这边写的线程才能开始进行写的复制操作!
基本的字节流:
一次读取一个字节/一次读取一个字节数组
字节缓冲流:
一次读取一个字节/一次读取一个字节数组
字符转换流:
InputStreamReader(InputStream in)
OutputStreamWriter(OutputStream out)
一次读取一个字符/一次读取一个字符数组
转换流的便捷类
FileReader(String name)
FileWriter(String writer)
一次读取一个字符/一次读取一个字符数组
public class CopyFile {
public static void main(String[] args) {
BufferedReader br = null ;
BufferedWriter bw = null ;
try {
br = new BufferedReader(new FileReader("ReaderDemo.java")) ;
bw = new BufferedWriter(new FileWriter("copy.java")) ;
String line = null ;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
bw.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
7.SequenceInputStream
SequenceInputStream: 字节流的逻辑串联!
可以将两个或者是两个以上的文件进行读的操作 ,只能操作源文件构造方法
public SequenceInputStream(InputStream s1,InputStream s2)
参数1和参数2:分别要读取的字节输入流对象
1)合并两个文件
现在:合并流
当前项目a.java+b.java---->当前项目下的c.java文件中
将当前项目下的BufferedWriterDemo.java+copy.java文件---->复制到当前项目下b.java文件中
public class CopyMulFile {
public static void main(String[] args) throws Exception {
InputStream is = new FileInputStream("BufferedWriterDemo.java") ;
InputStream is2 = new FileInputStream("copy.java") ;
SequenceInputStream sis = new SequenceInputStream(is,is2) ;
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.java")) ;
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len = sis.read(bytes))!=-1){
bos.write(bytes,0,len); }
bos.close();
sis.close();
}
}
2)合并两个以上文件
public SequenceInputStream(Enumeration<? extends InputStream> e) :将两个以上的文件进行读取 Vector<InputStream> add(添加多个字节输入流对象)
需求:
BufferedWriterDemo.java
ReaderDemo.java
CopyMp4.java
复制到D://hello.java文件中
public class CopyFileDemo2
{
public static void main(String[] args) throws Exception {
InputStream is1 = new FileInputStream("BufferedWriterDemo.java") ;
InputStream is2 = new FileInputStream("ReaderDemo.java") ;
InputStream is3 = new FileInputStream("CopyMp4.java") ;
Vector<InputStream> vector = new Vector<>() ;
vector.add(is1) ;
vector.add(is2) ;
vector.add(is3) ;
SequenceInputStream sis = new SequenceInputStream(enumeration);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d://hello.java")) ;
int by = 0 ;
while((by=sis.read())!=-1){
bos.write(by);
bos.flush();
}
bos.close();
sis.close();
}
}
8.序列化
序列化:ObjectOutputStream
将某个实体对象写入到流对象中---->将一个对象变成 流数据
构造方法
protected ObjectOutputStream()
protected ObjectOutputStream(OutputStream out) :
将某个对象通过底层的基本字节输出进行写的动作
public final void writeObject(Object obj) throws IOException
需求:将Person p = new Person("高圆圆",42) ;---->变成流对象 进行传输反序列化:ObjectInputStream
将流数据----还原成 "对象"
构造方法
public ObjectInputStream(InputStream in)
public final Object readObject() throws IOException, ClassNotFoundException
NotSerializableException:未实现序列化接口的异常
一个类在进行序列化的时候,(将类的对象写入序列化流中),标记接口Serializable 它有个特点
为当前这个Person进行编码(为类以及类的成员----->序列化化版本ID(签名):SerialversonUID)
java.io.InvalidClassException: com.qf.serailizable_05.Person; local class incompatible:
stream classdesc serialVersionUID = 2588921225545403990,
local class serialVersionUID = -862808041229244683
在进行序列化的时候:当前的 serialVersionUID:序列化版本id号 (假设100): 内存中生成一个id值
在进行反序列化的时候:将流--->对象 :
Person类的字段信息更改了(类的签名信息就会被更改),那么直接进行反序列化产生serialVersionUID=(假设200) 序列化版本id保证,
在idea中生成一个固定的序列版本id号 (一般都针对实体类)
一个实体类:
1)当前类必须为具体类 class 类名{}
2)必须存在私有字段(私有成员变量)
3)必须提供公共的setXXX()/getXXX()
4)如果当前类需要在网络中进行传输(分布式系统中)必须implements Serializable
idea- file--->setting---->editor---->Inspections----->java---->序列化serializion issue --->serializable class 打上对钩即可!
public class ObjectStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
myRead() ;
}
private static void myRead() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt")) ;
Object object = ois.readObject();
ois.close();
System.out.println(object);
}
private static void myWrite() throws IOException {
Person p = new Person("高圆圆",42) ;
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt")) ;
oos.writeObject(p);
oos.close();
}
}public class Person implements Serializable {
private static final long serialVersionUID = 8988325735017562383L;
String name ;
private transient int age ;
public Person(){
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
对多个对象进行操作
class Person0 implements Serializable{
private static final long serialVersionUID = 9166507990237193254L;
private String name ;
private int age ;
public Person0() {
}
public Person0(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; }
@Override
public String toString() {
return "Person0{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
read();
}
public static void read() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Object.txt"));
Object obj =null;
while((obj=ois.readObject())!=null) {
System.out.println(obj);
}
ois.close();
}
private static void write() throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Object.txt"));
Person0 p1 = new Person0("Mike",22);
Person0 p2 = new Person0("Like",44);
oos.writeObject(p1);
oos.writeObject(p2);
oos.writeObject(null);
oos.close();
}
}
9.Properties
Properties extends Hashtable<K,V> ,它没有泛型,Key和Value都是String
表示一组持久的属性。 Properties可以保存到流中或从流中加载。
属性列表中的每个键及其对应的值都是一个字符串。
1)可以使用Map的功能
put(K ,V)
遍历:
keySet()通用
2)有自己特有功能添加元素和遍历
public Object setProperty(String key,String value):给属性列表中添加属性描述(key和value)
public Set<String> stringPropertyNames():获取属性列表中的所有的键
public String getProperty(String key):在属性列表中通过键获取值
public class PropertiesDemo {
public static void main(String[] args) {
Properties properties = new Properties() ;
properties.put("高圆圆","赵又廷") ;
properties.put("文章","姚笛") ;
properties.put("文章","马伊琍") ;
properties.put("王宝强","马蓉") ;
Set<Object> keySet = properties.keySet();
for(Object key :keySet){
Object value = properties.get(key);
System.out.println(key+"---"+value);
}
System.out.println("---------------------------------------");
Properties prop = new Properties() ;
prop.setProperty("张三","30") ;
prop.setProperty("李四","40") ;
prop.setProperty("王五","35") ;
prop.setProperty("赵六","45") ;
Set<String> set = prop.stringPropertyNames();
for(String key:set){
String value = prop.getProperty(key);
System.out.println(key+"---"+value);
}
}
}
文件操作
Propeties:键和值都是字符串类型:可能需要在src(类所在的路径:类路径)作为一个配置文件
xxx.properties
将字节输入流或者字符输入中所在的文件中的内容加载属性列表中
void load(Reader reader)
void load(InputSteram in)
将Properties里面存储的内容----->保存到某个目录的xxx配置文件中 保存
public void store(Writer writer,String comments)
public void store(OutputStream out,String comments)
将属性列表中的内容保存到指定字节输出流/字符输出流所指向那个文件中
需求:
有一个文本文件
username.txt
key1=value1
key2=value2
....
...
将文本文件中的内容读取到属性列表中Properties 加载
将字节输入流或者字符输入中所在的文件中的内容加载属性列表中
void load(Reader reader)
void load(InputSteram in)
将Properties里面存储的内容----->保存到某个目录的xxx配置文件中 保存
public void store(Writer writer,String comments)
public void store(OutputStream out,String comments)
将属性列表中的内容保存到指定字节输出流/字符输出流所指向那个文件中
public class PropertiesDemo2 {
public static void main(String[] args) throws IOException {
myStore() ;
}
private static void myStore() throws IOException {
Properties prop = new Properties() ;
prop.setProperty("张三丰","56") ;
prop.setProperty("吴奇隆","60") ;
prop.setProperty("成龙","65") ;
prop.setProperty("刘德华","70") ;
prop.store(new FileWriter("user.txt"),"name's list'");
System.out.println("保存完毕");
}
private static void myLoad() throws IOException {
Properties prop = new Properties() ;
System.out.println(prop);
Class clazz = PropertiesDemo2.class ;
ClassLoader classLoader = clazz.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream("names.properties");
prop.load(inputStream);
System.out.println(prop);
Set<String> keySet = prop.stringPropertyNames();
for(String key:keySet){
String value = prop.getProperty(key);
System.out.println(key+"---"+value);
}
}
}
xxx.txt操作
public class Test3 {
public static void main(String[] args) throws IOException {
Properties prop = new Properties() ;
Reader r = new FileReader("user.txt") ;
prop.load(r);
Set<String> keySet = prop.stringPropertyNames();
for (String key : keySet) {
if("lisi".equals(key)){
prop.setProperty(key,"45") ;
}
}
Writer w = new FileWriter("user.txt") ;
prop.store(w,"name's lis");
}
}
23.网络编程
网络编程------>Socket编程
特点:
发送端/客户端
接收端/服务器端 这两端必须存在Socket对象
网络编程的三要素:
举例:
我要找到高圆圆 说一句话
1)ip:
知道高圆圆的ip地址
2)port 0-65535 (0-1024属于保留端口)
知道高圆圆的端口号
3)规定一种协议
协议:
udp协议
1)不需要建立连接通道
2)属于一种不可靠连接
4)执行效率高 (不同步的)
TCP/Ip协议
1)建立连接通道
2)属于安全连接(可靠连接)
3)发送文件(使用基本字节流),相对udp协议来说没有限制
4)执行效率低(同步的)
InetAddress:互联网ip地址
获取InetAddress:ip地址对象
public static InetAddress getByName(String host):参数:主机名称(计算机电脑名称)
public String getHostAddress():获取ip地址字符串形式
public class NetDemo {
public static void main(String[] args) throws UnknownHostException {
InetAddress inetAddress = InetAddress.getByName("DESKTOP-Q62EUJH");
String ip = inetAddress.getHostAddress();
System.out.println(ip);
}
}
1.udp通信
public class UdpSend {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket() ;
byte[] bytes = "hello,马三奇".getBytes() ;
int length = bytes.length ;
InetAddress inetAddress = InetAddress.getByName("10.12.156.107");
int port = 12306 ;
DatagramPacket dp = new DatagramPacket(bytes,length,inetAddress,port) ;
ds.send(dp);
ds.close();
}
}
public class UdpReceive {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(12306) ;
byte[] bytes = new byte[1024] ;
int lentgth = bytes.length ;
DatagramPacket dp = new DatagramPacket(bytes,lentgth);
ds.receive(dp);
byte[] bytes2 = dp.getData();
int length2 = dp.getLength();
String receiverStr = new String(bytes2,0,length2) ;
String ip = dp.getAddress().getHostAddress();
System.out.println("data from "+ip+" ,content is :"+receiverStr);
}
}
发送端不断键盘录入数据,接收端不断接收数据,然后展示内容
接收端端不断的接收数据
接收端一般不关闭
接收端只能开启一次,多次就出现 BindException:绑定一次
Address already in use: Cannot bind:端口号被占用!
public class UdpSend {
public static void main(String[] args) {
DatagramSocket ds = null ;
try {
ds = new DatagramSocket() ;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
String line = null ;
while((line=br.readLine())!=null){
if("886".equals(line)){
break ;
}
DatagramPacket dp = new DatagramPacket(line.getBytes(),
line.getBytes().length,
InetAddress.getByName("10.12.156.107"),6666);
ds.send(dp);
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
ds.close();
}
}
}
public class UdpReceive {
public static void main(String[] args) {
try {
DatagramSocket ds = new DatagramSocket(6666) ;
while(true){
byte[] bytes = new byte[1024] ;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length) ;
ds.receive(dp);
String receiveStr = new String(dp.getData(), 0, dp.getLength());
String ip = dp.getAddress().getHostAddress();
System.out.println("data from "+ip+"data is--->"+receiveStr);
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
}
}
}
2.TCP通信
TCP特点:需要建立连接通道(就是以一种字节流的方式写入,读取)
什么时候建立连接(服务器端如果监听到端口,客户端就立即和服务器端建立连接!)
TCP客户端写数据
1)创建TCP客户端的Socket对象
2)写数据
3)释放资源
TCP服务器端的实现步骤:
1)创建服务器端的Socket对象
public ServerSocket(int port)throws IOException
2)监听客户端连接
public Socket accept()throws IOException 返回值就是当前监听到的客户端的Socket对象
3)获取通道内的输入流
public InputStream getInputStream() throws IOException
4)读取数据:一次读取一个字节数组
5)展示数据 而且获取ip地址
//public InetAddress getInetAddress()
public class ScoketDemo {
public static void main(String[] args) throws IOException {
Socket s = new Socket("10.12.156.107",8888) ;
OutputStream out = s.getOutputStream();
out.write("hello,TCP".getBytes());
s.close();
}
}
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8888) ;
System.out.println("服务器正在等待连接...");
Socket socket = ss.accept();
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024] ;
int len = inputStream.read(bytes);
String clientStr = new String(bytes,0,len) ;
String ip = socket.getInetAddress().getHostAddress();
System.out.println("data from "+ip+" content is--->"+clientStr);
ss.close();
}
}
一个有回复的TCP通信
public class ScoketDemo {
public static void main(String[] args) throws IOException {
Socket s = new Socket("10.12.156.107",8888) ;
OutputStream out = s.getOutputStream();
out.write("hello,TCP".getBytes());
InputStream in = s.getInputStream();
byte[] bytes = new byte[1024] ;
int len = in.read(bytes);
String fkMsg = new String(bytes,0,len) ;
System.out.println("fkMsg:"+fkMsg);
s.close();
}
}
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8888) ;
System.out.println("服务器正在等待连接...");
Socket socket = ss.accept();
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024] ;
int len = inputStream.read(bytes);
String clientStr = new String(bytes,0,len) ;
OutputStream outputStream = socket.getOutputStream();
outputStream.write("ok,数据已经收到".getBytes());
outputStream.flush();
String ip = socket.getInetAddress().getHostAddress();
System.out.println("data from "+ip+" content is--->"+clientStr);
ss.close();
}
}
可以连续发送的TCP通信
客户端:
1)TCP客户端不断键盘录入数据,服务器端不断接收数据,然后展示数据
2)TCP客户端文本文件(XXX.java文件)----->服务器端将文件进行读写复制,输出到当前项目的Copy.java文件中
BuferedReader
3)TCP客户端文本文件(XXX.jpg文件)----->服务器端将文件进行读写复制,输出到当前项目的Copy.jpg文件中
BufferedInputStream
public class ClientDemo {
public static void main(String[] args) {
Socket socket = null ;
try {
socket = new Socket("10.12.156.107",10010) ;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
String line = null ;
while((line=br.readLine())!=null){
if("over".equals(line)){
break ;
}
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())) ;
bw.write(line);
bw.newLine();
bw.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public class ServerDemo {
public static void main(String[] args) {
ServerSocket ss = null ;
try {
ss = new ServerSocket(10010) ;
while(true){
System.out.println("服务器正在等待连接");
Socket socket = ss.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())) ;
String line = null ;
while((line=br.readLine())!=null){
System.out.println(line);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
发送文本文件并有反馈
客户端的一个文本文件,服务器端进行复制到指定的某个文件中 ,复制完毕了,服务器端需要给客户端反馈!(反馈的消息,客户端能不能获取到)
加入反馈操作:出现客户端和服务器端互相等待的情况--->但是文件已经复制完毕!
针对服务器端:不知道客户端是否还需要从通道内的输出流对象中写入数据(此时文件读写复制结束条件:只是null)
文件读完毕的条件是null,但是TCP通过流的方式 要进行结束; 服务器端不知道客户端是否还需要写入数据,客户端等待着服务器反馈的数据!
解决方案:
1)自定义结束条件
在客户端读完文件中,通知一下服务器端
写入一行内容("886/over"),服务器端只要读取到886或者over
2)可以使用客户端Socket的一个方法 标记(通知服务器端,客户端已经没有数据输出了)
public void shutdownOutput()throws IOException
public class ClientTest {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("10.12.156.107",10086) ;
BufferedReader br = new BufferedReader(new FileReader("Test.java")) ;
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())) ;
String line = null ;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
socket.shutdownOutput();
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024] ;
int len = inputStream.read(bytes);
String fkMsg = new String(bytes,0,len) ;
System.out.println("客户端到读取的反馈数据是:"+fkMsg);
br.close();
socket.close();
}
}
public class ServerTest {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086) ;
Socket socket = ss.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())) ;
BufferedWriter bw = new BufferedWriter(new FileWriter("copy.java")) ;
String line = null ;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
OutputStream outputStream = socket.getOutputStream();
outputStream.write("数据已经收到了,已经复制完毕".getBytes());
outputStream.flush();
bw.close();
ss.close();
}
}
客户端的图片文件
public class ClientImgDemo {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("10.12.156.107",12306) ;
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d://mm.jpg")) ;
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream()) ;
byte[] buffer = new byte[1024] ;
int len = 0 ;
while((len=bis.read(buffer))!=-1){
bos.write(buffer,0,len);
bos.flush();
}
socket.shutdownOutput();
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024] ;
int length = inputStream.read(bytes);
System.out.println("反馈内容为:"+new String(bytes,0,length));
bis.close();
socket.close();
}
}
public class ServlerImgDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(12306) ;
Socket socket = ss.accept() ;
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream()) ;
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("高圆圆.jpg")) ;
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
bos.flush();
}
OutputStream outputStream = socket.getOutputStream();
outputStream.write("图片文件复制完毕".getBytes());
outputStream.flush();
bos.close();
ss.close();
}
}
24.反射
什么是反射?
能够获取当前某个类的字节码文件对象Class,那么就可以获取当前类的构造器并且创建当前类实例,
还可以获取当前类的成员变量并去赋值,或者获取当前类的成员方法并去调用!
1.字节码文件
如何获取一个类的字节码文件对象?
1)Object类的getClass()获取 获取当前某个类的实例(正在运行的类)
2)任意Java类型的class属性
3)Class类的静态功能
public static Class<?> forName(String className)
Person类—下同
public class Person {
private String name ;
public int age ;
String address ;
public Person(){}
Person(String name,int age){
this.name = name ;
this.age = age ;
}
private Person(String name,int age,String addrss){
this.name = name ;
this.age = age ;
this.address = addrss ;
}
public void show(){
System.out.println("show Person");
}
private String functioin(String str){
return str ;
}
void method(String message,int num){
System.out.println(message+num);
}
public int method2(){
return 100 ;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
Person p = new Person() ;
Class c1 = p.getClass();
System.out.println(c1);
Person p2 = new Person() ;
Class c2 = p2.getClass() ;
System.out.println(c2);
System.out.println(c1==c2);
System.out.println(p==p2);
System.out.println("----------------------------");
Class c3 = Person.class ;
System.out.println(c3);
System.out.println(c1==c3);
System.out.println("-----------------------------");
Class c4 = Class.forName("com.qf.reflect_03.Person");
System.out.println(c4);
System.out.println(c1==c4);
}
}
2.创建对象
1.获取构造方法:
1)public Constructor<?>[] getConstructors():获取当前字节码文件对象中(正在运行的这个类)里面所有的公共的构造方法所在的对象
2)public Constructor<?>[] getDeclaredConstructors():获取所有的构造器对象Constructor,返回构造器对象数组 包含私有化构造/默认的
3)public Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) :参数都是参数类型的字节码文件对象
4)public Constructor<T> getConstructor(Class<?>... parameterTypes) :
( ... :jdk5以后 可变参数 (参数数量未知) )
获取指定的公共的单个的构造器对象 参数:需要书写的是当前参数类型的字节码文件对象
public void setAccessible(boolean flag)参数为true,取消Java语言访问检查
public T newInstance(Object... initargs): 参数为最终赋值的实际参数 (可变参数:实际参数未知)
public class ReflectDemo {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Person p = new Person() ;
System.out.println(p);
System.out.println("-----------------------------------------");
Class personClass = Class.forName("com.qf.reflect_03.Person") ;
Constructor[] constructors = personClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
Constructor[] constructors = personClass.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
Constructor constructor = personClass.getConstructor();
Object obj = constructor.newInstance();
System.out.println(obj);
}
}
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.qf.reflect_03.Person") ;
Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
Object obj = constructor.newInstance("高圆圆", 20);
System.out.println(obj);
}
}
3.成员变量
获取方法:
public Field[] getFields()throws SecurityException: 获取所有的公共的成员变量Field
public Field[] getDeclaredFields(): 所有的字段所在的Field对象,这包括公共,受保护,默认(包)访问和私有字段,但不包括继承的字段。
public Field getField(String name):参数为字段名称,获取单个成员变量
public Field getDeclaredField(String name): 获取指定的单个的字段所在的Field对象 , 参数为"当前字段名称",这包括公共,受保护,默认(包)访问和私有字段,但不包括继承的字段。
public class ReflectDemo {
public static void main(String[] args) throws Exception {
Person p = new Person() ;
System.out.println(p);
p.age = 20 ;
System.out.println(p);
System.out.println("-----------------------------");
Class clazz = Class.forName("com.qf.reflect_03.Person") ;
Object obj = clazz.newInstance();
System.out.println(obj);
Field[] fields = clazz.getFields() ;
for (Field field : fields) {
System.out.println(field);
}
Field[] fields = clazz.getDeclaredFields() ;
for (Field field : fields) {
System.out.println(field);
}
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj,"高圆圆");
System.out.println(obj);
System.out.println("-----------------------------------------------");
Field ageField = clazz.getField("age");
ageField.set(obj,20);
System.out.println(obj);
System.out.println("-----------------------------------------");
Field addressField = clazz.getDeclaredField("address");
addressField.setAccessible(true);
addressField.set(obj,"西安市");
System.out.println(obj);
}
}
4.成员方法
如何通过反射获取成员方法所在的Method,并能去调用
1)public Method[] getMethods(): 获取所有的成员方法:公共的(包含他父类的所有的公共的方法)
2)public 方法[] getDeclaredMethods(): 通过此表示类对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法
3)public Method getMethod(String name,Class<?>... parameterTypes)
参数1:方法名
参数2:当前这个方法所携带的参数类型的Class
4)public Method getDeclaredMetho(String name,Class<?> ..parameterTypes): 获取指定的单个的字段所在的成员方法 , 参数为"当前字段名称",这包括公共,受保护,默认(包)访问和私有字段,但不包括继承的字段。
public Object invoke(Object obj,Object... args):将方法的实际参数绑定在当前类的实例上
public class ReflectDemo {
public static void main(String[] args) throws Exception{
Person p = new Person() ;
p.show();
System.out.println("--------------------------");
Class clazz = Class.forName("com.qf.reflect_03.Person") ;
Object obj =clazz.newInstance() ;
Method showMethod = clazz.getMethod("show");
showMethod.invoke(obj) ;
System.out.println("--------------------------------------");
Method functonMethod = clazz.getDeclaredMethod("functioin", String.class);
functonMethod.setAccessible(true);
Object returnObj = functonMethod.invoke(obj, "hello,洪学佳,别睡了...");
System.out.println(returnObj);
}
}
5.应用
public class ReflectTest {
public static void main(String[] rgs) throws Exception {
ArrayList<Integer> arrayList = new ArrayList<>() ;
arrayList.add(100) ;
arrayList.add(50) ;
arrayList.add(200) ;
System.out.println(arrayList);
Class clazz = arrayList.getClass();
Method addMethod = clazz.getMethod("add", Object.class);
addMethod.invoke(arrayList, "hello");
addMethod.invoke(arrayList, "world");
addMethod.invoke(arrayList, "javaEE");
System.out.println(arrayList);
}
}
需求;
现在有一个学生类以及工人类,两类都有一个love方法
ReflectTest2在测试类中进行测试
1)起初,创建的一个学生对象,调用love方法
2)代码更改,创建一个工人类对象,调用love方法
如何将上面的代码进行优化!
Java设计原则:
开闭原则:对修改关闭,对扩展开放 (在现有代码进程上,想办法进行扩展...)
如果提供配置文件,以后只需要修改配置文件中内容,而不更改当前的代码!
如果能将配置文件,如果能加载属性集合列表中
className=com.qf.reflect_06.Worker
methodName=love
就可以通过key--->value
com.qf.reflect_06.Worker:创建当前类的字节码文件对象
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.qf.reflect_03.Person");
Constructor con = clazz.getDeclaredConstructor(String.class , int.class , String.class) ;
con.setAccessible(true);
Object obj = con.newInstance("高圆圆", 20, "西安市");
System.out.println(obj);
}
}
public class Worker {
public void love(){
System.out.println("爱生活,爱drink...,爱足球");
}
}
public class Student {
public void love(){
System.out.println("爱学习,爱Java,爱高圆圆...");
}
}
public class ReflectTest2 {
public static void main(String[] args) throws Exception {
InputStream inputStream = ReflectTest2.class
.getClassLoader().
getResourceAsStream("myClass.properties");
Properties prop = new Properties() ;
prop.load(inputStream);
System.out.println(prop);
String className = prop.getProperty("className") ;
String methodName = prop.getProperty("methodName") ;
Class clazz = Class.forName(className) ;
Object obj = clazz.newInstance() ;
Method method = clazz.getMethod(methodName) ;
method.invoke(obj) ;
}
}
25.数据库
DDL语句:数据库定义语句
1.库的增删查改
1.查询当前mysql下所有的数据库
mysql8.0 自带的 跟5.5自带的不一样
mysql> show databases;
+
| Database |
+
| information_schema | mysql默认的一些配置
| mysql | mysql库里面包含user表用户表 (权限用户)
| performance_schema | mysql性能相关的库
| sakila | 提供其他三个库 sakila sys world 提供了一些例库 练习sql语句
| sys |
| world |
| zy | 自定义的库(开发者自定义)
+
7 rows in set (0.00 sec)
2.创建数据库
create database 库名 ;
方式1
mysql> create database mydb_01;
Query OK, 1 row affected (0.02 sec)
create database if not exists 库名;
方式2
mysql> create database if not exists mydb_02;
Query OK, 1 row affected (0.02 sec)
3.查看创建数据库的默认的字符集(了解)
show create database 库名;
mysql> show create database mydb_01;
+
| Database | Create Database |
+
| mydb_01 | CREATE DATABASE `mydb_01` |
+
1 row in set (0.00 sec)
4.修改数据库的字符集(了解)
alter database 库名 (default)可以省略 character set=字符集;
mysql> alter database mydb_01 default character set gbk ;
Query OK, 1 row affected (0.01 sec)
mysql> show create database mydb_01;
+
| Database | Create Database |
+
| mydb_01 | CREATE DATABASE `mydb_01` |
+
1 row in set (0.00 sec)
mysql>
5.删除库
drop database 库名;
drop database if exists 库名;
mysql> drop database mydb_02;
Query OK, 0 rows affected (0.02 sec)
mysql> drop database if exists mydb_03;
Query OK, 0 rows affected (0.01 sec)
mysql> show databases;
+
| Database |
+
| information_schema |
| mydb_01 |
| mysql |
| performance_schema |
| sakila |
| sys |
| world |
| zy |
+
6.模糊查询mysql服务中所有的带character字符集的全局变量
show variables like '%character%' ;
mysql> show variables like '%character%' ;
+
| Variable_name | Value |
+
| character_set_client | gbk |
| character_set_connection | gbk |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | gbk |
| character_set_server | utf8mb4 |
| character_set_system | utf8mb3 |
| character_sets_dir | C:\Program Files\MySQL\MySQL Server 8.0\share\charsets\ |
+
8 rows in set, 1 warning (0.01 sec)
如果出现中文乱码:
character_set_client 客户端 utf8
character_set_results 结果集 utf8
改动字符集:临时解决中文乱码
mysql> set character_set_client=utf8;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> set character_set_results=utf8;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show variables like '%character%' ;
+
| Variable_name | Value |
+
| character_set_client | utf8mb3 |
| character_set_connection | gbk |
| character_set_database | ut
f8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb3 |
| character_set_server | utf8mb4 |
| character_set_system | utf8mb3 |
| character_sets_dir | C:\Program Files\MySQL\MySQL Server 8.0\share\charsets\ |
+
8 rows in set, 1 warning (0.00 sec)
2.表的增删改查
1.创建表
create table 表明(
列名1 字段类型1,
列名2 字段类型2,
...
列名n 字段类型n
) ;
数据库常用的字段类型
int
id int,
int(长度):指定长度
id int(3) 1
varchar(字符长度):字符串类型数据 '' "" 不写 引号 ,习惯去使用''或者双引号
double(值1,值2):小数类型
举例
double(3,2)
123.56
日期类型
date 仅仅表示日期,不表示时分秒
"2021-8-12"
datatime 不仅表示日期具体的时间
"2021-8-12 17:31:00"
timestap:时间戳
给表中插入数据, 显示当前插入/修改/删除/查询数据那一刻时间 (具体到秒"2021-8-12 18:00:01")
注意事项:就是给那一个库中创建表 使用哪个库(选择数据库名)
use 库名;
mysql> use mydb_01;
Database changed
mysql>
mysql> create table student(
-> id int,
-> name varchar(20),
-> gender varchar(10),
-> address varchar(50),
-> age int
-> )
-> ;
Query OK, 0 rows affected (0.05 sec)
2.查询当前数据库中有哪些表
show tables ;
mysql> show tables;
+
| Tables_in_mydb_01 |
+
| student |
+
1 row in set (0.01 sec)
3.查询当前表的结构
desc 表名 ;
mysql> desc student;
+
| Field | Type | Null | Key | Default | Extra |
+
| id | int | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
| gender | varchar(10) | YES | | NULL | |
| address | varchar(50) | YES | | NULL | |
| age | int | YES | | NULL | |
+
5 rows in set (0.01 sec)
修改表
4.给student表添加一列
alter table 表名 add 字段名称 字段类型;
mysql> alter table student add email varchar(50) ;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc student;
+
| Field | Type | Null | Key | Default | Extra |
+
| id | int | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
| gender | varchar(10) | YES | | NULL | |
| address | varchar(50) | YES | | NULL | |
| age | int | YES | | NULL | |
| email | varchar(50) | YES | | NULL | |
+
6 rows in set (0.01 sec)
5.修改表中的字段类型
alter table 表名 modify 字段名称 更改后的字段类型;
mysql> alter table student modify address varchar(30) ;
Query OK, 0 rows affected (0.07 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc student;
+
| Field | Type | Null | Key | Default | Extra |
+
| id | int | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
| gender | varchar(10) | YES | | NULL | |
| address | varchar(30) | YES | | NULL | |
| age | int | YES | | NULL | |
| email | varchar(50) | YES | | NULL | |
+
6 rows in set (0.00 sec)
6.修改表中的字段名称
alter table 表名 change 旧列名 新列名 字段类型;
mysql> alter table student change gender sex varchar(10) ;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc student;
+
| Field | Type | Null | Key | Default | Extra |
+
| id | int | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
| sex | varchar(10) | YES | | NULL | |
| address | varchar(30) | YES | | NULL | |
| age | int | YES | | NULL | |
| email | varchar(50) | YES | | NULL | |
+
6 rows in set (0.01 sec)
7.删除某一列字段
alter table 表名 drop 字段名称;
mysql> alter table student drop email;
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc student;
+
| Field | Type | Null | Key | Default | Extra |
+
| id | int | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
| sex | varchar(10) | YES | | NULL | |
| address | varchar(30) | YES | | NULL | |
| age | int | YES | | NULL | |
+
5 rows in set (0.01 sec)
8.修改表的表名
alter table 旧表名 renameto 新表名;
mysql> alter table student rename to stu;
Query OK, 0 rows affected (0.03 sec)
mysql> show tables;
+
| Tables_in_mydb_01 |
+
| stu |
| teacher |
+
2 rows in set (0.01 sec)
9.复制一张表结构和以前表的结果一样
create table 新表名 like 旧表名;
mysql> create table teacher like student;
Query OK, 0 rows affected (0.03 sec)
mysql> show tables;
+
| Tables_in_mydb_01 |
+
| student |
| teacher |
+
2 rows in set (0.01 sec)
10.删除表
drop tabble 表名;
drop table if exists 表名;
mysql> drop table if exists teacher;
Query OK, 0 rows affected (0.03 sec)
mysql> show tables;
+
| Tables_in_mydb_01 |
+
| stu |
+
1 row in set (0.00 sec)
DML语句:操作表的记录
11.插入语句
1)**insert into 表名 values(值1,值2,值3…) ;**插入全表数据 :那么每一个参数值必须和字段类型匹配! (不会报错,警告)
mysql> insert into stu values(1,'高圆圆','女','西安市',30) ;
Query OK, 1 row affected (0.01 sec)
插入全表:一次性插入多条数据
2)insert into 表名 values(值1,值2…),(值1,值2…),(值1,值2…) ;
INSERT INTO
stu
VALUES
(3,'文章','男','西安市',35),
(4,'马伊琍','女','上海市',42),
(5,'德玛西亚','男','艾欧尼亚',25) ;
插入部分字段
3) insert into 表名(部分字段1,字段2…) values(值1,值2…)
INSERT INTO
stu(NAME,sex,address) VALUES('王宝强','男','咸阳市') ;
12.最基本的查询:查全表数据
select * from 表名;
mysql> insert into stu values(1,'高圆圆','女','西安市',30) ;
Query OK, 1 row affected (0.01 sec)
mysql> select * from stu ;
+
| id | name | sex | address | age |
+
| 1 | 高圆圆 | 女 | 西安市 | 30 |
+
1 row in set (0.01 sec)
如果中文乱码
改动下面的字符集编码即可
mysql> show variables like '%character%' ;
+
| Variable_name | Value |
+
| character_set_client | gbk |
| character_set_connection | gbk |
| character_set_database | gbk |
| character_set_filesystem | binary |
| character_set_results | gbk |
| character_set_server | utf8mb4 |
| character_set_system | utf8mb3 |
| character_sets_dir | C:\Program Files\MySQL\MySQL Server 8.0\share\charsets\ |
+
8 rows in set, 1 warning (0.00 sec)
mysql> set character_set_client = utf8;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> set character_set_results = utf8;
Query OK, 0 rows affected, 1 warning (0.00 sec)
13.修改表的数据
语法:按条件修改 update
1)update 表名 set 字段名称 = 值 where 字段名称= 值;
UPDATE stu SET id = 7 WHERE NAME = '王宝强' ;
UPDATE stu SET age = 37 WHERE id = 7 ;
一次修改多个字段 2)update 表名 set 字段名称1 =值1 ,字段名称2 =值2 where 条件;
UPDATE
stu
SET
NAME = '张三丰',
sex = '男'
WHERE
id = 6 ;
3)如果不带条件修改:就是批量修改
UPDATE stu SET NAME = '高圆圆' ;
14.删除表中数据
1)带条件来删除 delete from 表名 where 字段名称 = 值; //删除指定的记录
DELETE FROM stu WHERE id = 6 ;
DELETE FROM stu WHERE id = 6 ;
2)删除全表数据 delete from 表名;
DELETE FROM stu ;
truncate table 表名;
TRUNCATE TABLE stu ;
删除全表的语法
delete from 表名;
truncate table 表名; 两个区别
1)delete from 表名:只是删除全表数据;表的结构还存在,
如果表中 存在主键并且自增长约束,那么不会受影响,下一次在插入数据
继续在之前的基础上继续自增长!
2)truncate table 表名 ;
将表中数据删除的同时删除了表,然后在创建一张一模一样空表,
肯定影响自增长主键的值,再次插入数据,自增长从1开始...
等价于
drop table my_use;
创建一个当前一模一样的表结构
CREATE TABLE my_user(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
age INT ,
gender VARCHAR(5)
) ;
INSERT INTO my_user(NAME ,age ,gender)
VALUES('张三',20,'男'),('李四',22,'女'),('文章',25,'男') ;
INSERT INTO my_user(NAME,age,gender) VALUES('王五',18,'男') ;
DELETE FROM my_user ;
TRUNCATE TABLE my_user ;
SELECT * FROM my_user;
3.查询表的数据
DQL之基本的查询语句
1)查询全表数据
? SELECT * FROM 表名 ;
实际开发中,* (通配符),一般查询全表数据,需要带全部字段
2)select 字段名称列表 from 表名;
SELECT
id ,
NAME,
sex,
address,
age
FROM stu ;
SELECT
id ,
NAME ,
address,
age
FROM stu ;
3)查询指定字段时可以通过as 关键字指定别名,as可以省略
SELECT
id AS '学生编号',
NAME AS '姓名',
address AS '地址',
age AS '年龄'
FROM stu ;
SELECT
id '学生编号',
NAME '姓名',
address '地址',
age '年龄'
FROM stu ;
1.where条件查询
DQL带条件查询
where条件查询
可以基本运算符:比较运算符(<,>,<=,>=,!=)/逻辑运算符(|| && /and /or)/赋值运算符 =
where后面多个or in(集合数据) 在两个值之间 between 值1 and 值2
mysql 判断某个字段为null , is null /is not null
模糊查询 like
聚合函数 count(列名)/max(列名)/min(列名)/sum(列名)/avg(列名)
排序查询 order by
分组查询 group by
筛选查询 having
分页查询limit
CREATE TABLE student (
id INT,
NAME VARCHAR(20),
age INT,
sex VARCHAR(5),
address VARCHAR(100),
math INT,
english INT
);
INSERT INTO student(id,NAME,age,sex,address,math,english) VALUES
(1,'马云',55,'男',' 杭州',66,78),
(2,'马化腾',45,'女','深圳',98,87),
(3,'马景涛',55,'男','香港',56,77),
(4,'柳岩 ',20,'女','湖南',76,65),
(5,'柳青',20,'男','湖南',86,NULL),
(6,'刘德华',57,'男','香港 ',99,99),
(7,'马德',22,'女','香港',99,99),
(8,'德玛西亚',18,'男','南京',56,65);
SELECT
id '编号',
NAME '姓名',
age '年龄',
sex '性别',
address '地址',
math '数学成绩',
english '英语成绩'
FROM
student
WHERE
age > 20 ;
SELECT
*
FROM
student
WHERE
age >= 20 && age <=30 ;
SELECT
*
FROM
student
WHERE
age >= 20 AND age <=30 ;
SELECT
NAME '姓名',
age '年龄',
address '地址',
math '数学成绩',
english '英语成绩'
FROM
student
WHERE
age
BETWEEN 20 AND 30 ;
SELECT
id '编号',
NAME '姓名',
age '年龄',
address '地址'
FROM
student
WHERE
age = 18 OR age = 20 OR age = 30 ;
SELECT
id '编号',
NAME '姓名',
age '年龄',
address '地址'
FROM
student
WHERE
age IN(18,20,30) ;
查询null
SELECT
id ,
NAME,
sex,
address,
math,
english
FROM
student
WHERE
english IS NULL ;
SELECT
id ,
NAME,
sex,
address,
math,
english
FROM
student
WHERE
english IS NOT NULL ;
SELECT
id 编号 ,
NAME 姓名 ,
sex 性别 ,
address '地址',
(math+IFNULL(english,0)) '总分'
FROM
student ;
**mysql 内置函数ifnull(值1,值2) ; **
IFNULL(english,0) :
字段去重 distinct
SELECT
DISTINCT address 地址
FROM student ;
SELECT
*
FROM student
WHERE age != 20 ;
SELECT
*
FROM
student
WHERE
age <> 20 ;
2.模糊查询
糊查询mysql服务中带字符集相关的变量 show variables like '%character%' ;
模糊查询 like
select 字段列表 from 表名 where 字段名称 like '%字符%' ;
% :包含的指定的字符 使用'%字符值%' 模糊查询包含指定字符的信息
_ :代表单个字符(一个_下划线代表一个字符)
两个相结合使用: '_%字符值%_' 三个字符:中间字符包含指定的值进行模糊查询
SELECT
*
FROM
student
WHERE
NAME
LIKE
'%马%' ;
SELECT
*
FROM
student
WHERE
NAME
LIKE
'_化%' ;
SELECT
*
FROM
student
WHERE
NAME
LIKE
'___' ;
3.聚合函数查询
聚合函数查询---- >查询结果:单行单列的数据
count(列名) :总记录数 count(列名)查询总记录数的时候,一般都使用非业务字段查询
max(列名): 最大值
min(列名字段):最小值
sum(字段名称):求和
avg(列名):平均分
select 聚合函数(列名) from 表名;
查询当前student这个表的全部总记录数
SELECT
COUNT(english)
FROM
student ;
SELECT
COUNT(IFNULL(english,0)) 总记录数
FROM
student;
SELECT
COUNT(id) 总条数
FROM
student ;
SELECT
AVG(math) '数学平均成绩'
FROM
student ;
SELECT
SUM(IFNULL(english,0)) 英语总分
FROM
student ;
SELECT
MAX(IFNULL(english,0)) 英语最高分
FROM
student ;
SELECT
MIN(math) 数学最低分
FROM
student ;
4.order by
排序查询:order by 字段名称 asc/desc (升序/降序)
select 字段列表 from 表名 order by 字段名 排序规则; -- 单个字段进排序
SELECT
*
FROM
student
ORDER BY math ;
SELECT
NAME ,
age,
sex,
address,
IFNULL(english,0) 英语成绩
FROM
student
ORDER BY english DESC ;
SELECT
*
FROM
student
ORDER BY
math DESC,
english ASC ;
5.group by
分组查询:group by
分组group by 分组字段;
查询的时候可以查询分组字段,
group by 后面不能使用聚合函数
SELECT
sex '性别',
COUNT(id) '人数'
FROM
student
GROUP BY
sex ;
SELECT
sex '性别',
COUNT(id) '总人数',
AVG(math) '数学平均成绩'
FROM
student
WHERE
math > 70
GROUP BY
sex ;
6.HAVING
筛选 having
having 必须置于group by 之后,where 置于 group by 之前
group by不能聚合函数,但是having后面可以聚合函数
SELECT
sex '性别',
COUNT(id) '总人数',
AVG(math) '数学平均成绩'
FROM
student
WHERE
math > 70
GROUP BY
sex
HAVING
COUNT(id) > 2 ;
SELECT
sex 性别,
COUNT(id) 总人数,
AVG(math) 数学平均成绩
FROM
student
WHERE
math > 70
GROUP BY
sex
HAVING
总人数 > 2 ;
having 与 where 的区别
where 子句
1) 对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,即先过滤再分组。
2) where 后面不可以使用聚合函数
having 子句
1) having子句的作用是筛选满足条件的组,即在分组之后过滤数据,即先分组再过滤。
2) having后面可以使用聚合函数
7.分页查询limit
select 字段列表 from 表名 limit 起始行数,每页显示多少条;
limit 起始行数=(当前页码数-1)*每页显示的条数,每页显示条数;
SELECT * FROM student LIMIT 0,3 ;
SELECT * FROM student LIMIT 3 ,3 ;
SELECT * FROM student LIMIT 6,3 ;
SELECT * FROM student LIMIT 9,3 ;
SELECT * FROM student ;
4.数据库约束
约束用户操作表的一种行为
1)默认约束
默认约束:防止出现非法数据null(没有插入造成null值)
当前没有给那个字段设置值的时候,此时默认约束就会起作用
gender VARCHAR(2) DEFAULT '女'
如果没有默认约束:
可能用户操作数据库的时候,插入非法数据(没有意义的数据)
如果没有给某个字段赋值,默认值null
CREATE TABLE test(
id INT ,
NAME VARCHAR(10) ,
gender VARCHAR(2) DEFAULT '女'
) ;
INSERT INTO test VALUES(1,'张三','男') ;
ALTER TABLE test MODIFY gender VARCHAR(2) ;
ALTER TABLE test MODIFY gender VARCHAR(2) DEFAULT '女' ;
DELETE FROM test WHERE id = 3 ;
2)非空约束
DROP TABLE test ;
CREATE TABLE test(
id INT ,
NAME VARCHAR(10) NOT NULL
);
INSERT INTO test VALUES(1,NULL) ;
3)唯一约束
nuique
DROP TABLE test;CREATE TABLE test( id INT , NAME VARCHAR(10), phone VARCHAR(11) UNIQUE
INSERT INTO test VALUES(1,'张三','13666668888') ;
INSERT INTO test VALUES(2,'李四','13666668889') ;
ALTER TABLE test DROP INDEX phone ;
INSERT INTO test VALUES(4,'赵六','13666668878') ;
DELETE FROM test WHERE id = 4 ;
ALTER TABLE test MODIFY phone VARCHAR(11) UNIQUE ;
4)主键约束
主键约束 (非空+唯一特点) primary key
都会给当前非业务字段去设置主键(xxid)
DROP TABLE test ;
CREATE TABLE test(
id INT PRIMARY KEY ,
NAME VARCHAR(10),
gender VARCHAR(2)
) ;
INSERT INTO test VALUES(1,'洪学佳','男'),(2,'马三奇','男') ;
alter table test drop primary key;
alter table test add primary key(id);
|