为您推荐:
精华内容
最热下载
问答
  • 5星
    26.34MB weixin_51390582 2021-08-02 10:32:24
  • 5星
    201.2MB qq_43045275 2021-03-19 10:42:22
  • 28.16MB weixin_43998595 2019-01-29 16:06:28
  • HTML速成的一些必要知识点来说一下。 一、基本 1、 标签:有图有真相,还附赠礼物。 标签不只是这么简单。它在段落和文本中还不一样。 段落控制: 表示paragraph,创建一个段,属性align表示段的对齐方式,#可以是...

    看了HTML孙鑫视频后,对HTML有了基本明确的掌握,梳理知识点对其进行一下总结。

    首先我们要了解我们为什么要学习HTML,我们搞Web开发,不可避免要接触HTML。JSP也是要学习到的知识,先来简单认识一下,它是一种动态网页开发的技术。我们经常要在HTML中嵌入Java代码,作为JSP开发人员,必须掌握一些常用的HTML标记。

    认识一下HTML,全称:Hypertext Markup Language,超文本标记语言。Web页面,或者说是网页,HTML就是来编写此文档的一种标记语言。

    HTML速成的一些必要知识点来说一下。

    7e5ab0799e606277b570c64b09d37685.png

    一、基本

    1、 标签:有图有真相,还附赠礼物。

    a2c4bdfd7aeb2b6a968c345c7b460464.png

    标签不只是这么简单。它在段落和文本中还不一样。

    段落控制:

    表示paragraph,创建一个段,属性align表示段的对齐方式,#可以是left、center、right、justify。

    表示link break,作用:换行

    表示horizontal rule,作用:插入一条水平线。

    文本显示:

    ...

    使文本居中显示

    ...

    用于指出文档的标题,n是从1到6的整数,1表示最大标题,6表示最小标题。属性align用户设置标题对齐的格式,#可以是left、center、right。

    ...

    用于设置字体。

    ...

    使文本成为粗体

    ...

    使文本成为斜体

    2、四种形式:大道至简,总结得太好了。

    (1)空元素

    (2)带有属性的空元素

    (3)带有内容的元素 http://www.baidu.com

    (4)带有内容和属性的元素 http://www.baidu.com

    这里需要注意的是,不同形式,这里标签是不一样的。

    3、框架:看完这个框架,你对HTML算是有了一个大概的认识了。图来得直接些。

    6946e709a57dea08e9db49b6fd81d3a3.png

    4、注释

    HTML文档一定要有注释啊,维护修改起来方便。注释展现:,例如

    拓展:特殊字符,先上图,随后用到再回来查找。常用的字符实体:

    bff867a871aeb28ba5d2719d3d7f2902.png

    二、运用

    1、列表

    (1)建立数字编号的列表

    使用和

    标签,在标签中使用start属性,设置起始的序号,在

    标签中使用value属性改变列表内的编号顺序。

    在和

    标签中,使用type属性指定编号系统的类型。具体看表。

    48055e75fb3c1d6b8ccabdd466794c00.png

    (2)建立带有项目符号的列表

    使用和

    ,type属性指定符号的样式,取值如下:

    e7ed7cb3018dfb58868c8b729f2d915d.png

    (3)建立无符号的列表

    使用与,使用标签替换,创建缩进的列表。

    知识点总结得再好看得也是醉了,真枪实弹地来个实例。

    《红楼梦》

    《西游记》

    《三国演义》

    《水浒传》

    《红楼梦》

    《西游记》

    《三国演义》

    《水浒传》

    《红楼梦》

    《西游记》

    《三国演义》

    《水浒传》

    《红楼梦》

    《西游记》

    《三国演义》

    《水浒传》

    《红楼梦》

    《西游记》

    《三国演义》

    《水浒传》

    《红楼梦》

    《西游记》

    《三国演义》

    《水浒传》

    《红楼梦》

    《西游记》

    《三国演义》

    《水浒传》

    《红楼梦》

    《西游记》

    《三国演义》

    《水浒传》

    《红楼梦》

    《西游记》

    《三国演义》

    《水浒传》

    《红楼梦》

    《西游记》

    《三国演义》

    《水浒传》

    网页效果:

    bc98e667bcfb5944a9dc79e245421c12.png

    2、表格

    ...

    用于定义表格的标题

    ...

    在表格中添加一个新行,属性align用于指定这一行在水平方向上的对齐方式,alignment可以是left、center、right。属性valign用于指定这一行在垂直方向上的对齐方式,alignment可以是top、middle、bottom

    ...

    用于定义表头

    ...

    用于定义单元格

    来吧,理论实践相结合,上实例吧。

    html文档:

    表格的例子

    2015年度上半年期末考试成绩单

    姓名

    语文

    数学

    英语

    张三

    100

    98

    80

    李四

    100

    98

    80

    王五

    100

    98

    80

    网页展示效果:

    125dbb86927e66798fd84b96c905a9fc.png

    3、表单

    表单创建...

    method用于指向服务器发送表单数据时所使用的HTTP方法。get是缺省的方法,当采用get方法提交表单时,提交的数据被附加到URL(在属性aciton中指定)的末端,作为URL的一部分发送到 服务器端。post方法是将表单中的信息作为一个数据块发送到服务器端。属性action指定对表单进行处理的脚本的地址。

    其中我们要用到元素。

    属性type用来指定要创建的控件的类型。name属性在表单中并不显示。属性size用来指定表单中控件的初始宽度。属性value指定控件的初始值。

    收藏一下元素。

    9c75f1232da68984ca566b66bd2c3e61.png

    用户填写注册信息的时候,输入个人简历,单行的文本输入控件不适合,怎么接受多行输入信息,我们可以使用多行文本输入控件。

    ...

    属性rows用于指定文本输入控件可视区域显示的宽度。在开始标签和结束标签之间出现的文本,将作为文本输入控件中的初始文本而显示。

    赶紧来实例验证一下。

    html文档:

    表单的例子

    用户名:

    密码:

    性别:

    兴趣爱好:

    篮球

    足球

    排球

    羽毛球

    最高学历:

    ...

    博士

    硕士

    学士

    高中

    个人简介:

    个人简介

    网页效果:

    b89a9a35269748c0eae395c1a4c591c0.png

    福利: 超链接

    HTML文本之所以被称为超文本,就是因为它具有普通文本不具有的超链接功能。能够通过点击关键字来实现页面的跳转。

    建立链接:...

    属性href用于指定链接的目标,目标地址由URL定位,在开始标签和结束标签之间输入的文本将作为浏览器中显示的链接文本。

    网页可以嵌入图像,基本语法为:

    URL

    属性src指定图像资源的位置,属性width和height用于指定图片的尺寸。

    要想理解透彻,还得看一下例子。

    网页效果:

    61f2e7dbe5a141f179d9bff45e15feb1.png

    效果可不是这么简单,点击任何一个关键字,它都能跳转到相应的页面。

    HTML也就这么些东西,不过细节的东西还有很多,无足大碍,以上内容有兴趣可以尝试编写一下,真正感受一下 html的魅力之所在。要想编写出更好的网页结构,还需要对html进一步的学习。

    展开全文
    weixin_30846347 2021-06-26 11:20:51
  • Java速成eclipse快捷键计算器程序面试题__一、Java基础编程--------方法与对象的使用1.面向对象编程(三条主线)①Java类及类的成员②面向对象的三大特征③其他关键字2.面向对象的两个要素3.设计类__4.类和对象的...

    Java速成

    eclipse快捷键

    eclipse中补全代码快捷键,默认Alt+/
    get、set方法: alt + shift +s

    代码助手:Ctrl+Space(简体中文操作系统是Alt+/)
    快速修正:Ctrl+1
    单词补全:Alt+/
    打开外部Java文档:Shift+F2
    显示搜索对话框:Ctrl+H
    快速Outline:Ctrl+O
    打开资源:Ctrl+Shift+R
    打开类型:Ctrl+Shift+T
    显示重构菜单:Alt+Shift+T

    上一个/下一个光标的位置:Alt+Left/Right
    上一个/下一个成员(成员对象或成员函数):Ctrl+Shift+Up/Down
    选中闭合元素:Alt+Shift+Up/Down/Left/Right
    删除行:Ctrl+D
    在当前行上插入一行:Ctrl+Shift+Enter
    在当前行下插入一行: Shift+Enter
    上下移动选中的行:Alt+Up/Down

    组织导入:Ctrl+Shift+O

    计算器程序

    package Triangle;
    import java.util.Scanner;
    public class calculator {
    
    	public static void main(String[] args) {
    		System.out.println("请输入a与b的值:");
    		Scanner s1 = new Scanner(System.in);
    		int a ,b , c;
    		a = s1.nextInt() ;
    		b =s1.nextInt() ;
    		System.out.println("请输入运算符:");
    		char s ;
    		s = s1.next().charAt(0) ;
    		
    		
    		if(s == '+') {
    			c = a + b;
    			System.out.println(a +"+"+b+"="+c );
    		}else if(s == '-') {
    			c = a - b;
    			System.out.println(a +"-"+b+"="+c );
    		}else if(s == '*') {
    			c = a * b;
    			System.out.println(a +"*"+b+"="+c );
    		}else if(s == '/') {
    			c = a / b;
    			System.out.println(a +"/"+b+"="+c );
    		}
    		
    	}
    
    }
    
    

    面试题

    ①final、finally、finalize的区别?
    ② == 和 equals() 的区别?

    一、Java基础编程

    --------方法与对象的使用

    1.面向对象编程(三条主线)

    ①Java类及类的成员

    类的成员:属性、方法、构造器、代码块、内部类

    ②面向对象的三大特征

    封装性、继承性、多态性、(抽象性)

    ③其他关键字

    this、super、static、final、abstract、interface、package、import 等

    2.面向对象的两个要素

    ①类
    对一类事物的描述,是抽象的、概念上的定义
    ②对象
    (对象必须基于类来创建。)
    是实际存在的该类事物的每个个体,因而也称为实例(instance)

    3.设计类

    其实就是设计类的成员
    属性 = 成员变量 = field = 域、字段
    方法 = 成员方法 = 函数 = method
    创建类的对象 = 类的实例化 = 实例化类

    4.类和对象的使用(面向对象思想落地的实现)

    ①创建类,设计类的成员
    ②创建类的对象
    ③通过 ”对象.属性“ 或 ”对象.方法“ 调用对象的结构
    ④如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)意味着:如果我们修改了一个对象的属性a的值,但不会影响另外一个对象属性a的值。

    5.对象的内存解析

    在这里插入图片描述
    在这里插入图片描述

    6.类中属性的使用

    属性(成员变量) VS 局部变量

    1、相同点:
    ①定义变量的格式:数据类型 变量名 = 变量值
    ②先声明,后使用
    ③变量都有其对应的作用域
    2、不同点:
    ① 在类中声明的位置不同
    属性:直接定义在类的一对{}内
    局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量。

    ②关于权限修饰符的不同
    属性:可以在声明属性时,指明其权限,使用权限修饰符。
    常用的权限修饰符:private、public、缺省、protected
    局部变量:不可以使用权限修饰符

    ③默认初始化值的情况不同
    属性:类的属性,根据其类型,都有默认初始化值。
    整型(byte、short、int、long) : 0
    浮点型 (float、double) : 0.0
    字符型 (char) : 0 (或 ‘\u0000’)
    布尔型 (boolean) : false
    引用数据类型(类、数组、接口) : null

    局部变量:没有默认初始化值。
    意味着,我们在调用局部变量之前,一定要显式赋值。
    特别的:形参在调用时,我们赋值即可。

    ④在内存中加载的位置不同
    属性:加载到堆空间中 (非static)
    局部变量:加载到栈空间

    7.类中方法的声明和使用

    ①方法的声明:

    权限修饰符 返回值类型 方法名(形参列表){ 方法体 }
    例:public static void main(String[] args){}
    注:static、final、abstract 来修饰方法。

    ②权限修饰符:

    java规定的4种权限修饰符:private 、public、protected、缺省
    ->>封装性时,细研

    ③返回值类型:

    有返回值 VS 没有返回值
    ①如果方法有返回值,则必须在方法声明时,指定返回值的类型。 同时,方法中,需要使用return关键字来返回指定类型的变量或常量。“return 变量/常量”
    ②如果方法没有返回值,则方法声明时, 使用void来表示 . 通常,没有返回值的方法中,就不使用return 但是,如果使用的话,只能"return;" 表示结束此方法的意思.

    ④方法名:

    属于标识符,遵循标识符的规则和规范,“见名知意”
    形参列表: 方法可以声明0个 、1个或多个形参。
    格式: (数据类型1 形参1 , 数据类型2 形参 2 , …)

    ⑤return关键字的使用:

    使用范围: 使用在方法中
    作用 :
    ①结束方法
    ②针对于有返回值类型的方法,使用"return 常量/变量(数据)" 方法返回所要的 数据. 注意点: return关键字后面不可以声明执行语句.

    ⑥方法的使用:

    可以调用当前类的属性或方法
    特殊的: 方法A 中又调用了方法A : 递归方法 .
    方法中,不可以再定义方法

    package lz3;
    
    public class CustomerTest {
    
    	public static void main(String[] args) {
    		
    		Customer C1 = new Customer() ;
            C1.eat();
            C1.name="yyz";
            System.out.println(C1.getName());
            System.out.println(C1.getNation("中国")) ;
            C1.sleep(8);
    	}
    	
    }
    	
    
    class Customer {
    	 //属性
    	 
    	 String name ;
    	 int age ;
    	 boolean isMale ;
    	 
    	 //方法 
    	 public void eat () {
    		 System.out.println("可以吃饭");
    	 }
    	 public void sleep(int hour) {
    		 System.out.println("休息了" + hour + "小时");
    		 eat();
    	 }
    	 public String getName() {
    		 return name;
    	 }
    	 public String getNation(String nation) {
    		 String info = "我的国籍是:" + nation;
    		 return info ;
    	 }
    	 
    }
    

    总结[ZONG]

    面向对象思想编程内容的三条主线分别是什么?

    面向对象编程思想内容的三条主线:
    ①类及类的成员:属性->方法->构造器->代码块->内部类

    ②面向对象的三大特征:封装->继承->多态

    ③其他关键字:this->super->abstract->interface->package->import

    谈谈你对面向对象中类和对象的理解,并指出二者的关系?

    类:抽象上的、概念上的内容
    对象:实实在在存在的一个个体。对象是由类派生出来的

    面向对象编程思想的体现一:类和对象的创建和执行操作有哪三步?

    ①创建类
    ②类的实例化
    ③调用对象的结构:”对象.属性“ ”对象.方法“

    虚拟机栈,即为平时提到的栈结构。我们将局部变量存储在栈结构中
    堆,我们将new出来的结构(比如:数组、对象)加载在堆空间中。补充:对象的属性(非static的)加载在堆空间中
    方法区:类的加载信息、常量池、静态域

    理解”万事万物皆对象“ ?

    1、在Java语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的结构

    2、涉及到Java语言与前端Html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类、对象

    内存解析的说明

    1、引用类型的变量,只可能储存两类值:null 或 地址值(含变量的类型)

    匿名对象的使用

    1、理解:我们创建的对象,没有显示的赋给一个变量名。即为匿名对象
    2、特征:匿名对象只能调用一次
    3、使用:或将匿名对象的地址值赋给另一个对象,可调用多次

    可变个数形参的方法

    1、可变个数形参的格式:数据类型 ... 变量名
    2、当调用可变个数形参的方法时,传入的参数可以是:0个,1个,2个…
    3、可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
    4、可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。
    5、可变个数形参在方法的形参中,必须声明在末尾
    6、可变个数形参在方法的形参中,最多只能声明一个可变形参

    package lz94;
    
    public class DeFormableGinseng {
    
    	public static void  main(String[] args) {
    		De f1 = new De() ;
    		f1.function(1,"2","3");
    		
    	}
    }
    
    class De {
    	
    	public void function (int a,String  b) {
    		System.out.println("int , String");
    	}
    	
    	public void function (int a ,String ... b) {
    		System.out.println("int , String...");
    	}
    	
    }
    

    关于变量的赋值:

    1、如果变量是基本数据类型,此时赋值的是变量所保存的数据值
    2、如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值(即,被赋值的那个变量的栈中的地址值指向的堆中的储存空间与赋值的那个值所指向的储存空间一样)

    package lz94;
    
    public class VariableAssignment {
    
    	public static void main (String[] args) {
    		variable m1 = new variable() ;
    		variable c = m1;
    		m1.a = 9 ;
    		m1.methods();
    		c.a =100 ;
    		c.methods();
    		m1.methods();
    		
    		
    	}
    }
    
    class variable{
    	int a ;
    	
    	public void methods() {
    		System.out.println("a="+a);
    	}
    	
    	
    	
    }
    

    方法的形参的传递机制,值传递

    1、形参:方法定义时,声明的小括号内的参数
    实参:方法调用时,实际传递给形参的数据

    2、值传递机制:
    如果参数是基本数据类型,此时实参赋给形参的是,实参真实存储的数据值。
    如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。

    封装性[FENG]

    封装性的设计思想

    隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。
    通俗化:把该隐藏的隐藏起来,该暴露的暴露出来。

    响应java程序设计追求 “高内聚,低耦合”
    高内聚:类的内部数据操作细节自己完成,不允许外部干涉
    低耦合:仅对外暴露少量的方法用于使用

    封装性的体现一

    我们将类的属性xxx私有化(private), 同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值。

    /* Encapsulation 封装性
     * animal 动物 
     * 
     * 封装性的体现:①属性私有化 ②不对外暴露的私有的方法 ③单例模式 .......
     * */
    
    
    public class animal {
    
    	public static void main (String[] args) {
    		rabble r1 = new rabble();
    		//r1.name = "jack";
    		//使用set方法给Age赋值
    		r1.setAge(11);
    		//调用eat方法
    		r1.eat();
    		//查看Age属性的值
    		System.out.println(r1.getAge());
    	} 
    	
    }
    
    class rabble {
    	 private String name ;
    	 private int Age ;
    	 private int Gender ;
    	// get() 与 set()方法 
    	public int getAge() {
    		return Age ;
    	} 
    	public void setAge(int a) {
    		Age = a ;
    	}
    	 
    	public void eat () {
    		System.out.println(name +"会吃饭"+",今年"+Age+"岁了"+",Gender是"+Gender);
    	}
    }
    

    封装性的体现二

    不对外暴露的私有的方法

    封装性的体现三

    单例模式(将构造器私有化)【static关键字后解锁 】

    封装性的体现四

    如果不希望类在包外被调用,可以将类设置为缺省的。

    封装性的体现…

    封装性的体现无处不在,只要是涉及到4种权限的修饰符,便体现了封装性。
    若没有Java的四种权限,便没有了封装性。
    封装性的体现,需要权限修饰符来配合。

    Java规定的四种权限修饰符

    ①java规定的4种权限(从小到大排列):private->缺省->protected->public

    ②4种权限都可以用来修饰类及类的内部结构:属性、方法、构造器、内部类

    ③修饰的话,只能使用: 缺省、public。

    ④具体的修饰范围
    在这里插入图片描述

    总结封装性

    Java提供了四种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时可见性的大小。

    构造器[GOU]

    1. eclipse构造器快捷键

    ①Alt+shift+s

    2. 构造器功能

    ①创建对象

    ②初始化对象信息

    3. 详细说明

    1. 如果没有显示的定义类的构造器,则系统会默认提供一个空参的构造器
    2. 定义构造器的格式: 权限修饰符 类名 (形参列表) {}
    3. 一个类中定义的对个构造器,彼此构成重载
    4. 一旦我们显示的定义了类的构造器之后,系统就不再提供默认的空参构造器
    5. 一个类中,至少会有一个构造器。
    package Constructor;
    
    public class TheConstructor {
    
    	public static void main(String[] args) {
    		person p1 = new person() ;
    		p1.eat();
    		person p2 = new person("jack",30) ;
    		p2.walk();
    		p1.setName("Tom ");
    		p1.walk();
    	}
    
    }
    
    
    
    class person {
    	//属性
    	private String name ;
    	private int Age ;
    	
    	//构造器
    	public person() {
        //空参构造器
    	}
    	private person(String n) {
    		name = n ;
    	}
    	public person(String m,int a) {
    		name = m ;
    		Age = a ;
    	}
    	
    	//方法
    	public void setName(String n) {
    		name = n ;
    	}
    	
    	public void eat () {
    		System.out.println("可以吃饭");
    	}
    	public void walk() {
    		System.out.println(name+"会走路");
    	}
    }
    
    package Triangle;
    
    public class Triangle1 {
    
    	public static void main(String[] args) {
    		TrianglE T1 = new TrianglE(4,6);
    		System.out.println(T1.getBase());    
    		System.out.println(T1.getHeight());   
    		T1.calculate();
    	} 
    
    }
    
    
    class TrianglE{
    	//属性
    	private int base ;
    	private int height;
    	
    	//构造器
    	public TrianglE() {
    		
    	}
    	public TrianglE (int a,int b) {
    		base = a ;  
    		height = b ;
    	}
    	
    	//方法
    	public void setBase(int a) {
    		base = a ;
    	}
    	public int getBase() {
    		return base;
    	}
    	public void setHeight(int a) {
    		height = a ;
    	}
    	public int getHeight() {
    		return height;
    	}
    	public void  calculate () {
    		int s ;
    		s=(base * height)/2 ;
    		System.out.println("底为:"+base +",高为:"+height+"的三角形的面积为:"+s);
    	}
    }
    
    

    4. 属性赋值的先后顺序

    ①默认初始化
    ②显示初始化
    ③构造器赋值
    ④通过“对象.方法” 或 “对象.属性” 的方式。赋值
    以上操作的先后顺序:① - ② - ③ - ④

    JavaBean

    JavaBean定义

    JavaBean 是一种Java语言写成的可重用组件。

    所谓JavaBean,是指符合如下标准的Java类:
    ①类是公共的
    ②有一个无参的公共的构造器
    ③有属性,且有对应的get、set方法

    JavaBean作用

    用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP页面、其他JavaBean、apple程序或者应用来使用这些对象。用户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。

    package JavaBean;
    //公共类
    //有一个无参的构造器
    //有属性的,且有对应get、set方法的
    
    public class Bean {
    
    	public static void main(String[] args) {
    		
    	}
    	//属性
    	private String name ;
    	private int a;
    	
    	//无参构造器
    	public Bean() {
    		
    	}
    	//get、set方法
    	public String getName() {
    		return name ;
    	} 
    	public void setName(String c) {
    		name = c ;
    	}
    	public int getA() {
    		return a ;
    	} 
    	public void setA(int c) {
    		a = c ;
    	}
    }
    
    

    关键字 this

    1、可以调用的结构

    this 可以用来修饰:属性、方法、构造器

    2、this 修饰属性和方法

    this理解为:当前对象 或 当前正在创建的对象

    2.1 在类的方法中,我们可以使用“this.属性” 或 “this.方法” 的方法,调用当前对象属性或方法。但是通常情况下,我们都选择省略“this.”。特殊情况下,如果方法的形参和类的属性同名时,我们必须显示的使用“this.变量”的方式,表明此变量是属性,而非形参。

    2.2 在类的构造器中,我们可以使用“this.属性” 或 “this.方法” 的方法,调用当前正在创建的对象属性或方法。但是通常情况下,我们都选择省略“this.”。特殊情况下,如果方法的形参和类的属性同名时,我们必须显示的使用“this.变量”的方式,表明此变量是属性,而非形参。

    3、this调用构造器

    ①:我们在类的构造器中,可以显示的使用 “this(形参列表 )” 方式,调用本类中指定的其他构造器
    ②:构造器中不能通过 “this(形参列表)” 方式调用自己
    ③:如果一个类中有n个构造器,则最多有n-1 个构造器使用了 “this(形参列表 )” ,剩下的那一个是super()。
    ④:规定: “this(形参列表 )” 必须声明在当前构造器的首行
    ⑤:构造器内部,最多只能声明一个 “this(形参列表 )” ,用来调用其他的构造器

    MVC设计模式

    模型层 model 主要处理数据

    控制层 controller 处理业务逻辑

    视图层 view 显示数据

    在这里插入图片描述

    复习问题[FU]

    ①构造器的作用是什么?使用中有哪些注意事项?
    ②关于类的属性的赋值,有几种赋值的方式。以及赋值的先后顺序
    ③this 关键字可以用来调用哪些结构
    ④java中目前学习涉及到的四种权限修饰符都有什么?并说各自的权限范围

    继承性[JI]

    1、继承性的特点

    ①减少代码冗余,提高了代码的复用性。
    ②便于功能的扩展
    ③为后续的多态性的使用,提供了前提

    2、继承性的格式

    calss A extends B{}
    # A为子类,B为父类
    

    2、继承性的体现

    2.1 体现:一旦子类A继承父类B以后,子类A就获取了父类B中声明的所有的属性和方法。
    特别的,父类中声明为private的属性或方法,子类继承父类后,仍然认为获取了父类中私有的结构。但因为封装性的影响,使得子类不能直接调用父类的结构。
    2.2 子类继承父类以后,还可以声明自己特有的属性和方法:实现功能的拓展

    3、继承性的规定

    1.一个类可以被多个子类继承
    2.Java中的类是单继承性:一个类只能有一个父类 (接口是多继承性)
    3.子父类是相对的概念。
    4.子类直接继承的父类,称为:直接父类。间接继承的父类成为:间接父类
    5.子类继承父类以后,就获取了直接父类以及所有父类中声明的属性和方法

    4、java.lang.Objeck类(默认父类)(间接父类)

    1.如果我们没有显示的声明一个类的父类的话,则此类继承于java.lang.Objeck类。
    2.所有的java类(除java.lang.Objeck类之外)都直接或间接的继承于java.lang.Objeck类
    3.意味着,所有的java类具有java.lang.Objeck类声明的功能。

    程序的调式——Debug调试

    ① 设置断点
    设置方法:(对“行数”双击)
    注:可设置多个断点
    ②右键-> debug as -> java application->yes
    ③常用操作

    操作作用
    step into 跳入(f5)进入当前行所调用的方法中
    step over 跳过(f6)执行完当前行的语句,进入下一行
    step return 跳回(f7)执行完当前行所在的方法,进入下一行
    drop to frame回到当前行所在方法的第一行
    resume 恢复执行完当前所在断点的所有代码,进入下一个断点,如果没有就结束

    方法的重写——(子类重写父类同名同参的方法)

    方法的重写(override / overwrite)

    1. 重写
      子类继承父类后,可以对父类中同名同参数的的方法。进行覆盖操作
    2. 应用
      重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写父类的方法。

    3. 重写的规定

    方法的声明: 权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型 {
    //方法体
    }
    约定俗称:子类中的叫重写方法,父类中的叫被重写的方法

    ①子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
    ②子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
    ③返回值类型
    a.父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
    b.父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
    c.父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的
    ④子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型

    特殊情况:子类不能重写父类中声明为private权限的方法


      子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写)。
    

    super 关键字

    1.super 理解为:父类的

    2. super 可以调用的结构:属性、方法、构造器

    3.super的使用

    3.1 我们可以在子类的方法或构造器中。通过使用“super.属性”或“属性.方法”的方式,显示的调用父类中声明的属性或方法。但是,通常情况下,我们习惯省略"super."
    3.2 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显示的使用“super.属性”的方式,表明调用的是父类中的属性。
    3.3 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显示的使用"super.方法"的方式,表明调用的是父类中被重写的方法。

    4. super调用构造器

    4.1 我们可以在子类的构造器中显示的使用“super(形参列表)”的方式,调用父类中声明的指定的构造器
    4.2 "super(形参列表)"的使用,必须声明在子类构造器的首行!
    4.3 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)“只能二选一,不能同时出现
    4.4 在构造器的首行,没有显示的声明"this(形参列表)“或"super(新参列表)”,则默认调用的是父类中空参的构造器:super()
    4.5 在类的多个构造器中,至少有一个类的构造器中使用了"super(形参列表)”,调用父类的构造器

    子类对象实例化的过程

    1.从结果上来看:就是(继承性)

     子类继承父类以后,就获取了父类中声明的属性或方法。
     创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。
    

    2. 从过程上来看

    当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的的构造器,进而调用父类的父类的构造器,直到调用了Java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类中的结构,子类对象才可以考虑进行调用。

    图示
    在这里插入图片描述

    3. 强调说明

    需要明确的是:虽然创建子类对象时,调用了父类的构造器,但是至始至终只创建过一个对象,那个对象就是 新new出来的子类对象。
    在这里插入图片描述

    多态性[DUO]

    1.多态性的理解

    可以理解为一个事物的多种形态。

    2.何为多态性

    对象的多态性:父类的引用指向子类的对象 (或子类的对象赋给父类的引用)

     举例:
     person p = new Man();
     Object obj = new Date();
    

    3.多态的使用 (虚拟方法调用)

    虚拟方法调用:
    有了对象的多态性以后,我们在编译期,只能调用父类声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
    总结:编译,看左边;运行,看右边

    虚拟方法调用(Virtual Method Invocation)

    ●正常的方法调用
    Person e = new Person();
    e.getlnfo();
    Studente = new Student();
    e.getlnfo();
    
    ●虚拟方法调用(多态情况下)

    子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。

    Person e = new Student();
    e.getInfo();  //调用Student类的getInfo()方法
    
    ●编译时类型和运行时类型

    编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo(方法。——动态绑定

    4.多态性的使用前提:

    ①类的继承关系
    ②方法的重写

    5. 多态性的应用举例

    举例一:

    public void fun(Animal animal){ //Animal animal = new Dog();
    	animal.eat();
    	animal.shout();
    }
    

    举例二:

    public void method(Object obj){
    	
    }
    

    举例三:

    calss Driver{
    	public  void doData(Connection conn){//conn = new MySqlConnection(); /conn = new OracleConnection(); 
    		//操作数据库
    //		conn.method1();
    //		conn.method2();
    //		conn.method3();
    	}
    }
    

    6. 多态性的注意点

    对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)

    7. 多态性的体现

    package learning10_6;
    
    //测试类
    public class AnimalTest {
    	
    	public static void main(String[] args) {
    		AnimalTest a1 = new AnimalTest(); 
    		a1.fun(new Dog());
    		a1.fun(new Cat());
    	}
    	public void fun(Animal animal) { //Animal animal = new Dog() 匿名对象
    		animal.eat();
    		animal.shout();
    	}
    }
    
    //父类
    class Animal{
    	public void eat() {
    		System.out.println("动物.吃");
    	}
    	public void shout() {
    		System.out.println("动物.叫");
    	}
    }
    //子类
    class Dog extends Animal{
    	public void eat() {
    		System.out.println("小狗吃骨头");
    	}
    	public void shout() {
    		System.out.println("汪!汪!汪!");
    	}
    }
    //子类
    class Cat extends Animal{
    	public void eat() {
    		System.out.println("小猫吃鱼儿");
    	}
    	public void shout() {
    		System.out.println("喵!喵!喵!");
    	}
    }
    
    

    8. 多态性-问题

    /*1.若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,
     * 系统将不可能把父类里的方法转移到子类里:编译看左边,运行看右边
     *2.对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,
     *这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边。 
     */
    package learning10_7;
    //-----------------------------------------------------
    class MissZhu{
    	int count = 10 ;
    	
    	public void learing() {
    		System.out.println(this.count);
    	}
    }
    //-----------------------------------------------------
    class ClassmateFang extends MissZhu{
    	int count = 20 ;
    	
    	public void learing() {
    		System.out.println(this.count);
    	}
    }
    //-----------------------------------------------------
    public class problemTest {
    	public static void main(String[] args) {
    		ClassmateFang c = new ClassmateFang();
    		System.out.println(c.count); //①问
    		c.learing(); //②问
    		MissZhu m = c ;
    		System.out.println(m==c);//③问
    		System.out.println(m.count);//④问
    		m.learing();//⑤问
    	}
    }
    //2020true1020
    
    

    小结:方法的重载与重写

    1.二者的定义细节,略
    2.从编译和运行的角度看:
    重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不同的参数表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类和子类的,即子类可以重载父类的同名不同参数的方法。所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定”;

    而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体方法,这称为“晚绑定”或“动态绑定”。

    引用一句Bruce Eckel的话:“不要犯傻, 如果它不是晚绑定,它就不是多态。”

    问题:区分方法的重写和重载?

    答:
    ①二者的概念
    ②重载和重写的具体规则
    ③重载:不表现为多态性
    重写:表现为多态性

    重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不同的参数表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类和子类的,即子类可以重载父类的同名不同参数的方法。所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定”;
    而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体方法,这称为“晚绑定”或“动态绑定”。
    引用一句Bruce Eckel的话:“不要犯傻, 如果它不是晚绑定,它就不是多态。”

    instanceof 操作符

    例:a instanceof A
    效果:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false
    使用情景:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,现进行instanceof的判断,一旦返回ture,就进行向下转型。如果返回false,不进行向下转型。
    特别的:有类B是类A看,如果a instanceof A返回true,则a instanceof B也返回true。
    在这里插入图片描述

    package learning10_7;
    
    public class Test_1 {
    	public static void main(String[] args) {
    		java_1 j1 = new java_2("龙同学",18,""); //虚拟方法的调用--当调用子父类同名同参数的方法时,
    		                                       //实际执行的是子类重写父类方法
    		j1.eat();
    		j1.name = "";
    //		j1.xxx ="" ; //不能调用子类所特有的方法、属性
    // --问题点:有了对象的多态性以后,内存中实际上是加载了子类特有的的属性和方法的,但是由于变量声明为父类类型
    // --,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。  
    // --------------so,如何才能调用子类特有的属性和方法?----------------------
    //---------------答:向下转型:使用强制类型转换符。--------------------------		
    		java_2 j2 = (java_2) j1 ;
    		j2.xxx = "" ;
    		j2.name = "鱼仔";
    		j2.learn();
    //---------------注:使用强制类型转换,可能出现ClassCastException的异常。		
    //	    java_3 j3 = (java_3) j1 ;
    //        j3.talk();
    		
    //-------------- instanceof  因此闪亮登场 -----------------------
    //------ a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。
    //------使用意境:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof
    //----------------的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
    //-------有类B是类A的父类,若 a instanceof A 返回ture,则 a instanceof B 一定返回true。
    		
    		if(j1 instanceof java_3) {
    			java_3 j3 = (java_3) j1 ;
    			j3.talk();
    			System.out.println("--------------java_3是类j1的实例----------------");
    		}else {System.out.println("--------------java_3不是类j1的实例----------------");}
    //-----------------------------------------------------------------------------------------------		
    		if(j1 instanceof java_2) {
    			java_2 j_2_2 = (java_2) j1 ;
    			j_2_2.learn();
    			System.out.println("--------------java_2_2是类j1的实例----------------");
    		}
    //-----------------------------------------------------------------------------------------------------
    // -----------------------练习---------------------
    		//①编译通过,运行通过   父类转子类
    		  Object p1 = new java_3("",0,0);   //父级类p1
    		  java_1 s1 =(java_1) p1 ;         //
    		  s1.eat();
    //           子类转父类
    		  java_2 p4 =new java_2("",0,"");
    		  java_1 s4 =(java_1) p4 ;
    		  s4.eat();
    	   //②编译通过,运行不过    父类转子类
    		  java_1 p2 = new java_3("",0,0);  // 父级类 p2
    //		  java_2 s2 = (java_2) p2 ;       //  将父级类p2-->子级类,并赋给子级类s2
    // 		  s2.learn();                    //调用子级类方法,运行系统报错
    	  //③编译不通过
    //		  java_2 p3 = new java_3("",0,0);
    		  
    		
    	}
    
    }
    

    Object类

    java.lang.Object类

    1.Object类是所有Java类的根父类

    2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类

    3.Object 类中的功能(属性、方法)就具有通用性。
    属性:无
    方法:equals() / toString() / getClass() / hashCode() / clone() / finalize() / wait() 、notify()、notifyAll()

    4.Object类只声明了一个空参的构造器

    1. equals()方法

    一、回顾 ‘==’ 运算符的使用:

    (1) 可以使用在基本数据类型变量和引用数据类型变量中
    (2)如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)
    (3)如果比较的是引用数据类型变量:比较两个对象的地址是否相同,即两个引用是否指向同一个对象实体

    二、equals()方法的使用:
    (1)是一个方法,并非运算符
    (2)只能适用于引用数据类型
    (3)Objeck类中equals()的定义(源码):

       public boolean equals(Object obj){
    			return (this == obj);
       }
    

    说明:Object类中定义的equals()和==的作用是相同的:
    比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体

    4.像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的”实体内容“是否相同。

    5.通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的“实体内容”是否相同。那么我们就需要对Object类中的equals()进行重写

    2. 面试题: ==和equals的区别

    ① ==既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型就是比较内存地址

    ②equals方法,它是属于java.lang.Object类里面的方法,如果该方法没有被重写过默认也是==;而String等类的equals方法是被重写过的,而且String类在日常开发中用的比较多,便形成了equals是比较值的错误观点

    ③具体要看自定义类里有没有重写Object的equals方法来判断

    ④通常情况下,重写equals方法,会比较类中的相应属性是否都相等

    3. 手动重写equals方法

    class dog {
    	String name;
    	int age ;
    	//重写equals()方法
    	public boolean equals(Object obj) {
    		if(obj ==  this) {
    			return true;
    		}
    		if(obj instanceof dog) {
    			 dog d1 = (dog)obj;
    			 return this.age == d1.age && this.name.equals(d1.name);
    		}
    		return false ;
    	}
    }
    

    开发中如何实现?:shift + Alt + s 自动生成

    4. 重写equals()方法的原则

    ①对称性:如果x.equals(y)返回是"true” ,那么y.equals(x)也应该返回是"true"。

    ②自反性: x.equals(x)必须返回是"true"

    ③传递性:如果x.equals(y)返回是"true”,而且y.equals(z)返回是"true",那么z.equals(x)也应该返回是"true" 。

    ④一 致性: 如果x.equals(y)返回是"true",只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是"true"。

    ⑤任何情况下, x.equals(null), 永远返回是“false";x.equals(和x不同类型的对象)永远返回是“false”。

    5. toString()方法

    Object类中toString()的使用:
     1.当我们输出一个对象的引用时,实际上就是调用当前对象的toString()
     2.Object类中toString的定义:
    	public String toString(){
    		return getClass().getName() + "@" +Integer.toHexString(hashCode());
    	} 
     3.StringDateFile、包装类等都重写了Object类中的toString()方法。
       使得在调用对象的toString()时,返回实体内容信息
     4.自定义类也可以重写toString()方法,当调用此方法时,返回对象的“实体内容”
    

    6. 重写toString方法

    //自动生成就行
    @Override
    	public String toString() {
    		return "dog [name=" + name + ", age=" + age + "]";
    	}
    

    包装类[BAO]

    1. 单元测试

    不用写main方法,直接在方法内测试相关代码

    Java中的JUnit单元测试
    步骤:
    1.选中当前工程 - 右键选择:build path -add libraries - JUnit 4 -下一步
    2. 创建Java类:进行单元测试。
    此时的Java类要求:①此类是public的 ②此类提供公共的无参的构造器
    3. 此类中声明单元测试方法。
    此时的单元测试方法:方法的权限是public,没有返回值,没有形参
    4. 此单元测试方法上需要声明注释:@Test,并在单元测试中导入:import org.junit.Test;
    5. 声明好单元测试方法以后,就可以在方法体内测试相关的代码。
    6. 写完代码以后,左键双击单元测试方法名,右键:run as - JUnit Test
    说明:
    1.如果执行结果没有任何异常:绿条
    2.如果执行结果出现异常:红条

    2. 基本类型、包装类与String类间的转换

    (1)为什么要有包装类(或封装类)

    为了使基本数据类型的变量具有类的特征,所以引入了包装类。

    (2)基本数据类型与对应的包装类

    其中,Byte、Short、Integer、Long、Float、Double的父类是Number。

    基本数据类型包装类
    byteByte
    shortShort
    intInteger
    longLong
    floatFloat
    doubleDouble
    booleanBoolean
    charCharacter

    (3)需掌握的:基本数据类型、包装类、String三者之间的相互转换

    简易版:
    ①基本数据类型< - - ->包装类:JDK5.0 新特性:自动装箱与自动拆箱
    ②基本数据类型、包装类 - - -> String:调用String重载的valueOf(Xxx xxx)
    ③String - - - >基本数据类型、包装类:调用包装类的parseXxx(String s)

    注意:转换时,可能会报NumberFormatException异常

    (4)应用场景举例:

    ①Vector类中关于添加元素,只定义了形参Object类型的方法

    v.addElement(Object obj); //基本数据类型--->包装类--->使用多态
    

    (5)相互转换举例

    基本数据类型< - - - > 包装类

    public void text1() {
    		
    		 // 自动装箱:基本数据类型--->包装类 
    		int num1 = 10 ;
    		Integer in1 = num1 ; //自动装箱
    		
    		boolean b1 = true ;  //自动装箱
    		Boolean b2 = b1 ;
    		
    		// 自动拆箱:包装类--->基本数据类型 
    		System.out.println(in1.toString());
    		
    		int num2 = in1 ;
    	}
    

    基本数据类型、包装类 - - - > String

    //基本数据类型、包装类--->String:调用String重载的valueOf(Xxx xxx)
    		@Test
    		public void text2() {
    			
    			int num1 = 100 ;
    			//方式一:连接运算
    			String str1 = num1 + ""  ;
    			//方式二:调用 String 的 valueOf(Xxx xxx)
    			float f1 = 1.23f ;
    			String str2 = String .valueOf(f1); // "12.3"
    			
    			Double d1 = new Double(12.4);
    			String str3 = String.valueOf(d1);
    			System.out.println(str2);
    			System.out.println(str3);
    			
    		}
    

    String - - - >基本数据类型、包装类

    //String--->基本数据类型、包装类:调用包装类的parseXxx(String s)
    		@Test
    		public void text3() {
    				String str1 = "123" ;
    				int num1 = Integer.parseInt(str1);
    				System.out.println(num1);
    				
    				String str2 = "true1" ;
    				boolean b1 = Boolean.parseBoolean(str2);
    				System.out.println(b1);
    			}
    

    (6)Integer细节小知识

    Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],保存了从-128~127范围的整数。
    如果我们使用自动装箱的方式,给Integer赋值的范围在-128~127范围时,可以直接使用数组中的元素,不用再去new了。
    目的:提高效率
    	public void test4(){
    		 Integer i = new Integer(1);
    		 Integer j = new Integer(1);
    		 System.out.println(i == j); //false
    		 
    		 Integer m = 1 ;
    		 Integer n = 1 ;
    		 System.out.println(m == n); //true
    		  
    		 Integer x = 128 ; //相当于new了一个Ingeter对象
    		 Integer y = 128 ; //相当于new了一个Ingeter对象
    		 System.out.println(x == y); //false 
       	}
    

    static 关键字

    1、static:静态的

    2、static可以用来修饰:属性、方法、代码块、内部类。

    3、使用static修饰属性:静态属性(或类变量)

    3.1属性:按是否使用static修饰,又分为:静态属性VS非静态属性(实例变量)

    静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。
    实例变量 :我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。

    3.2 static修饰属性的其他说明:

    ①静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用
    ②静态变量的加载要早于对象的创建。
    ③由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。
    类可以直接调用类中的类变量,但不能直接调用实例变量;对象可以调用类变量,也可以调用实例变量。

    3.3 静态属性举例: System.out; Math.PI; 单例模式 ;

    4、 使用static修饰方法:静态方法

    ①随着类的加载而加载,可以通过“类.静态方法”的方式进行调用
    类可以直接调用静态方法,但不能调用非静态方法;对象既可以调用静态方法也可以调用非静态方法。
    ③ **静态方法中,只能调用静态的方法或属性。**非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性。

    5、static 注意点:

    5.1 在静态的方法内,不能使用this关键字、super关键字
    5.2 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。

    6、如何判定属性是否要声明为static的?

    • 属性是可以被多个对象所共享的,不会随着对象的不同而不同。
    • 类中的常量也常常声明为static

    7、如何判定方法是否要声明为static的?

    • 操作静态属性的方法,通常设置为static的
    • 工具类中的方法,习惯上声明为static的。此如:math、Arrays、Collections

    Static应用举例:单例Singleton设计模式

    设计模式[SHE]

    定义:设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。
    作用:设计模免去我们自己再思考和摸索。式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,“套路”。

    1、类的单例设计模式

    要解决的问题:所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。

    并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
    特点
    由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
    例如:java.lang.Runtime 类,便是单例模式 ctrl + shitl + t输入类名查看源码

    2、如何实现单例模式?:饿汉式 VS 懒汉式

    单例设计模式的饿汉式

    package learning10_21;
    
    public class SingletonTest1 {
    	public static void main(String[] args) {
    		Bank bank1 = Bank.getInstance();
    		Bank bank2 = Bank.getInstance();
    		System.out.println(bank1 == bank2);
    	}
    }
    
    //单例设计模式的饿汉式
    class Bank{
    	//1.私有化类的构造器
    	private Bank() {
    		
    	}
    	//2.内部创建类的对象
    	//4.要求对象也必须声明为静态的
    	private static Bank instance = new Bank() ;
    	//3.提供公共的静态的方法,返回类的对象
    	public static Bank getInstance() {
    		return instance ;
    	}
    }
    

    单例模式的懒汉式:

    package learning10_21;
    //单例设计模式的懒汉式
    public class SingletonTest2 {
    	public static void main(String[] args) {
    		Cat cat1 = Cat.getInstance();
    		Cat cat2 = Cat.getInstance();
    		System.out.println(cat1 == cat2);
    	}
    }
    
    class Cat{
    	//1.私有化类的构造器
    	private Cat(){
    		
    	}
    	//2.声明当前类对象,没有初始化
    	//4.此对象也必须声明为static的	
    	private static Cat instance = null ;
    	//3. 声明public、static 的返回当前类对象的方法
    	public static Cat getInstance () {
    		if(instance == null) {
    			instance = new Cat() ; 
    		}
    		return instance ;
    	}
    }
    
    

    3、区分饿汉式和懒汉式

    饿汉式:
    弊端:  一上来就将对象创建好,导致对象加载时间过长。
    好处: 饿汉式是线程安全的。 
    懒汉式:
    好处: 延迟对象创建。
    当前写法坏处:线程不安全。--->到多线程内容时,再优化写法。
    

    4、单例设计模式应用场景

    • 网站的计数器,一般也是单例模式实现,否则难以同步。
    • 应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
    • 数据库连接池的设计一般也是采用单例模式, 因为数据库连接是一种数据库资源。
    • 项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。
    • Application也是单例的典型应用。
    • Windows的Task Manager (任务管理器)就就是很典型的单例模式
    • Windows的RecycleBin(回收站)也也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

    理解main方法的语法

    main方法的使用说明:
    1.main()方法作为程序的入口
    2.main()方法也是一个普通的静态方法
    3.main()方法可以作为我们与控制台交互的方式。(之前:使用Scanner)

    main()方法作为程序的入口.实例:

    package learning10_22;
    /*
     * main方法的使用说明
     * 1.main()方法作为程序的入口
     * 2.main()方法也是一个普通的静态方法
     * 3.main()方法可以作为我们与控制台交互的方式。(之前:使用Scanner)
     * */
    public class manTest {
    	public static void main(String[] args) {
    		main.main(new String[300]);
    	}
    }
    
    class main{
    	public static void main(String[] args) {
    		for(int i=0;i<args.length;i++) {
    			args[i] = "args_" + i ;
    			System.out.println(args[i]);
    		}
    	}
    }
    

    在这里插入图片描述

    main()方法可以作为我们与控制台交互的方式.实例:

    package learning10_22;
    
    public class mainDemo {
    	public static void main(String[] args) {
    		
    		for(int i=0;i<args.length;i++) {
    			System.out.println("********"+args[i]);
    			
    			int num = Integer.parseInt(args[i]);
    			System.out.println("#####" + num);
    		}
    	}
    }
    

    在这里插入图片描述
    在这里插入图片描述

    代码块[DAI]

    类的成员之四:代码块(或初始化块)

    1.代码块的作用:用来初始化类、对象

    2.代码块如果有修饰的话,只能使用static.

    3.分类:静态代码块 VS 非静态代码块

    3.1.静态代码块:

    ①内部可以有输出语句。
    ②随着类的加载而执行,而且只执行一次 (只要类没有重新加载,就不会再次执行)。
    ③作用:初始化类的信息。
    ④如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行。
    ⑤静态代码块的执行要优先于非静态代码块的执行。
    ⑥静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构。

    3.2.非静态代码块:

    ①内部可以有输出语句
    ②随着对象的创建而执行
    ③每创建一个对象,就执行一次非静态代码块
    ④作用:可以在创建对象时,对对象的属性等进行初始化
    ⑤如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
    ⑥非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法

    package learning10_22;
    public class BlockTest {
    	public static void main(String[] args) {
    		String desc = Person.desc ;
    		System.out.println(desc);
    		
    		Person p1 = new Person();
    		Person p2 = new Person();
    		Person p3 = new Person();
    		System.out.println(p1.age);
    	}
    }
    
    class Person{
    	//属性
    	String name;
    	int age ;
    	static String desc = "I am people" ;
    	//构造器
    	public Person() {
    		
    	}
    	public Person(String name,int age) {
    		this.name = name ;
    		this.age = age ;
    	}
    	//静态代码块
    	static{
    		System.out.println("hello,static block-1");
    		desc = "我是一个爱学习的人-来自于静态类";
    	}
    	static{
    		System.out.println("hello,static block-2");
    	}
    	//非static代码块
    	{
    		System.out.println("hello,block");
    		age = 1 ;
    	}
    	//方法
    	public void eat() {
    		
    	}
    	@Override
    	public String toString() {
    		return "Person [name=" + name + ", age=" + age + "]";
    	}
    	public static void info() {
    		System.out.println("I am happy man");
    	}
    	
    }
    

    在这里插入图片描述

    4.对属性可以赋值的位置:

    ①默认初始化
    ②显示初始化 / ⑤在代码块赋值
    ③构造器中初始化
    ④有了对象以后,可以通过"对象.属性"或"对象.方法"的方式。进行赋值

    赋值执行的先后顺序: ① - ②/⑤ - ③ - ④

    package learning10_22;
    /*
     * 对属性可以赋值的位置:
     * ①默认初始化
     * ②显示初始化 /  ⑤在代码块赋值
     * ③构造器中初始化
     * ④有了对象以后,可以通过"对象.属性"或"对象.方法"的方式。进行赋值
     * */
    public class OrderTest {
    	public static void main(String[] args) {
    		Order order = new Order();
    		System.out.println(order.OrderId);
    	}
    }
    
    
    class Order{
    	int OrderId= 3 ;
    	{
    		OrderId = 4 ;
    	}
    }
    

    在这里插入图片描述

    final 关键字

    1.final可以用来修饰的结构:类、方法、变量
    2.final用来修饰一个类:此类不能被其它类所继承
    比如:String类、System类、StringBuffer类
    3. final用来修饰方法:表明此方法不可以被重写
    比如:Object类中getClass();
    4. final用来修饰变量:此时的"变量"就称为是一个常量
    4.1final修饰属性:可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化。
    4.2 final修饰局部变量:尤其是使用final修饰形参时,表明此形参是一个常量 当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。

    抽象类与抽象方法

    1.abstract(关键字):抽象的

    2.abstract可以用来修饰的结构:类、方法

    3.abstract修饰类:抽象类

    • 此类不能实例化
    • 抽象类中一定有构造器,便于子类实例化时调用(设计:子类对象实例化的全过程)
    • 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作

    4.abstract修饰方法:抽象方法

    • 抽象方法只有方法的声明,没有方法体
    • 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法。
    • 若子类重写了父类中的所有的抽象方法后,此子类可以实例化
    • 若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰

    5.abstract使用上的注意点:

    1.abstract 不能用来修饰:属性、构造器等结构
    2.abstract不能用来修饰私有方法、静态方法、final的方法、final的类

    6.抽象类的匿名子类

    在这里插入图片描述

    7.模板方法设计模式(TemplateMethod) (多态的应用)

    抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象,类的行为方式。

    解决的问题:
    当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
    换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式。

    接口interface (关键字)

    接口的使用

    1.接口使用interface来定义

    2.Java中,接口和类是并列的两个结构

    3.如何定义接口:定义接口中的成员

    3.1 JDK7及以前:只能定义全局常量和抽象方法

    全局常量:public static final 的
    抽象方法:public abstrsct 的

    3.2 JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)

    4.接口中不能定义构造器!意味着接口不可以实例化

    5.Java开发中,接口通过让类去实现(implements)的方式来使用.

    如果“实现类”覆盖了接口中的所有抽象方法,则此实现类就可以实例化.
    如果“实现类”没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类.

    6.Java类可以实现多个接口 ---->弥补了Java单继承性的局限性

    格式:class AA extends BB implements CC,DD,EE…{}

    7. 接口与接口之间可以继承,而且可以多继承

    package learning10_27;
    
    public class InterfaceTest {
    	public static void main(String[] args) {
    		plane p1 = new plane();
    		p1.fly();
    		p1.stop();
    		Bullet b1 = new  Bullet() ;
    		b1.fly();
    		b1.stop();
    		b1.attack1();
    		b1.method1();
    		b1.method2();
    	}
    }
    
    //接口
    interface Fly{
    	//全局变量
    	public static final int MAX_SPEED = 7900 ; //第一宇宙速度
    	/*public static final*/ int MIN_SPEED = 1 ; //最慢速度 (可以省略public static final,但系统会自动加上)
    	
    	//抽象方法
    	public  void fly();
    	void stop();
    }
    
    //接口
    interface Attack{
    	public abstract void attack1();
    }
    
    
    
    //用plane类实现Fly接口
    class plane implements Fly{
    	@Override
    	public void fly() {
    		System.out.println("飞机飞飞飞");
    	}@Override
    	public void stop() {
    		System.out.println("飞机刹车刹车刹车");
    	}
    }
    
    //用kite实现Fly接口,但又没完全实现,还是得声明为abstract类
    abstract class kite implements Fly{
    	@Override
    	public void fly() {
    		
    	}
    }
    
    //用Bullet类实现Fly,Attack两个接口   
    class Bullet extends Object implements Fly,Attack,CC{
    	@Override
    	public void fly() {
    		System.out.println("子弹flyflyfly");
    	}
    	@Override
    	public void stop() {
    		System.out.println("子弹停停停");
    	}
    	@Override
    	public void attack1() {
    	System.out.println("biu~bui~bui~");	
    	}
    	@Override
    	public void method1() {
    	System.out.println("CC的方法一");
    	}
    	@Override
    	public void method2() {
    		System.out.println("CC的方法二");
    	}
    }
    //*******************************************************************************
    // 接口多继承
    interface AA{
    	public abstract void method1();
    }
    interface BB{
    	public abstract void method2();
    }
    interface CC extends AA,BB{
    	
    }
    
    

    在这里插入图片描述

    8. 接口的使用

    1.接口使用上也满足多态性
    2.接口,实际就是定义了一种规范
    3.开发中,体会面向接口编程

    从以下代码可以体现出:

    package learning10_27;
    /*
     * 接口的使用
     * 1.接口使用上也满足多态性
     * 2.接口,实际就是定义了一种规范
     * 3.开发中,体会面向接口编程
     * */
    public class USBTest {
    	public static void main(String[] args) {
    		computer c1 =new computer();
    		//1.创建了接口的非匿名实现类的非匿名对象
    		Printer p1 = new Printer() ;
    		c1.transferDate(p1);
    	    //2.创建了接口的非匿名实现类的匿名对象
    		c1.transferDate(new Printer());
    		//3.创建了接口的匿名实现类的非匿名对象
    		Usb phone = new Usb() {
    			
    			@Override
    			public void stop() {
    			System.out.println("phne工作");
    			}
    			@Override
    			public void start() {
    			System.out.println("phne停止");
    			}
    		};
    		c1.transferDate(phone);
    		//4.创建了接口的匿名实现类的匿名对象
    		c1.transferDate(new Usb() {
    			@Override
    			public void start() {
    				System.out.println("mp3开始工作");
    			}
    			@Override
    			public void stop() {
    				System.out.println("mp3停止工作");
    			}
    		});
    		
    	}
    }
    
    //电脑类
    class computer{
    	public void transferDate(Usb u) {
    		u.start();
    		System.out.println("传输细节");
    		u.stop();
    	}
    }
    
    
    
    //USB接口
    interface Usb{
    	//常量:定义了长、宽、最大最小的传输速度等
    	public abstract void  start();
    	public abstract void  stop();
    }
    
    //Flash类实现USB接口
    class Flash implements Usb{
    	@Override
    	public void start() {
    		System.out.println("U盘载入成功");
    	}
    	@Override
    	public void stop() {
    		System.out.println("U盘断开连接");
    	}
    }
    
    //Printer类实现Usb接口
    class Printer implements Usb{
    	@Override
    	public void start() {
    		System.out.println("打印机开启");
    	}
    	@Override
    	public void stop() {
    		System.out.println("打印机断开");
    	}
    }
    
    

    9.接口的应用:代理模式(proxy)

    概述:代理模式是Java中开发中使用比较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。

    例1 (安全代理:屏蔽对真实角色的直接访问)

    package learning10_27;
    /*
     * 接口的应用:代理模式
     * */
    public class NetWrokTest {
    	public static void main(String[] args) {
    		Server server = new Server() ;
    		ProxyServer proxyServer = new ProxyServer(server) ;
    		proxyServer.browse();
    	}
    }	
    
    //NetWork 接口
    interface NetWork{
    	public abstract void browse(); //浏览功能
    }
    
    //Server类实现NetWork接口 (被代理类)
    class Server implements NetWork{
    	@Override
    	public void browse() {
    		System.out.println("真实的服务器访问网络");
    	}
    }
    
    //ProxyServer类实现NetWork接口 (代理类)
    class ProxyServer implements NetWork{
    	
    	private NetWork work ;
    	public ProxyServer(NetWork work) {
    		this.work = work ;
    	}
    	
    	public void check() {
    		System.out.println("联网之前的检查工作");
    	}
    	
    	
    	@Override
    	public void browse() {
    		check();
    		work.browse();	
    	}
    }
    

    例二 (安全代理:屏蔽对真实角色的直接访问)

    package learning10_27;
    
    public class StarTest {
    	public static void main(String[] args) {
    		agent a = new agent(new Star());
    		a.sing();
    		a.talk();
    		a.money();
    	}
    }
    
    
    interface fun {
    	public abstract void sing();
    	public abstract void talk();
    	public abstract void money();
    }
    
    class Star implements fun{
    	@Override
    	public void sing() {
    	System.out.println("明星唱歌");
    	}
    	@Override
    	public void talk() {
    	System.out.println("谈生意");
    	}
    	@Override
    	public void money() {
    	System.out.println("拿钱");
    	}
    }
    
    
    class agent implements fun{
    	private fun f ;
    	//构造器
    	public agent(fun f) {
    		this.f = f ;
    	}
    	@Override
    	public void talk() {
    	System.out.println("经纪人谈生意");
    	}
    	@Override
    	public void money() {
    	System.out.println("经纪人拿钱");
    	}
    	@Override
    	public void sing() { //调用明星唱歌
    	f.sing();
    	}
    }
    

    应用场景:

    • 安全代理:屏蔽对真实角色的直接访问。
    • 远程代理:通过代理类处理远程方法调用(RMI)。
    • 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象比如你要开发一个大文档查看软件,大文档中有大的图片,有可能一个图片有100MB,在打开文件时,不可能将所有的图片都显示出来,这样就可以使用代理模式,当需要查看图片时,用proxy来进行大图片的打开。

    分类:

    • 静态代理(静态定义代理类)
    • 动态代理(动态生成代理类)
      JDK自带的动态代理,需要反射等知识

    10.接口的应用:工厂模式

    核心本质:
    实例化对象,用工厂方法代替new操作。
    将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。

    11.面试题

    在这里插入图片描述

    12.JAVA8中接口的新特性

    JDK8:除了定义全局常量抽象方法之外,还可以定义静态方法默认方法

    知识点1:接口中定义的静态方法,只能通过接口来调用。

    知识点2:通过实现类的对象,可以调用接口中的默认方法;如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法

    知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。–>>>类优先原则

    知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错。—>接口冲突
    这就需要我们必须在实现类中重写此方法

    知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法

    package learning10_28;
    
    public class aTest {
    	public static void main(String[] args) {
    		Sub s1 = new Sub();
    //		s1.method1();
    		CompareA.method1();
    		s1.method2();
    		s1.method3();
    	}
    }
    
    
    class Sub extends SuperClass implements CompareA,CompareB{
    	
    	public void method2() {
    		System.out.println("覆盖性上海");
    	}
    	public void method3() {
    		System.out.println("深圳");
    	}
    	public void myMethod() {
    		method3();//自己定义的重写方法
    		super.method3();//调用的是父类中的方法
    		//调用接口中默认方法
    		CompareA.super.method3();
    		CompareA.super.method2();
    	}
    }
    

    实例:
    当同时实现 Mother 与 Spoony 两个接口,又在Man中想调help方法时,就会报错 (显示两个接口中的方法重名)。
    需在Man中重写
    继承了Father类中的help方法,从而自动调用父类中的help方法。
    ③若想在Man中调用接口中的help方法,格式:接口名.super.help();

    package learning10_30;
    
    interface Mother{
    	default void help() {
    		System.out.println("老妈,我来救你了");
    	}
    }
    
    interface Spoony{
    	default void help() {
    		System.out.println("媳妇,别怕,我来了");
    	}
    }
    
    class Father{
    	public void help(){
    		System.out.println("儿子,救我媳妇");
    	}
    }
    
    public class Man extends Father implements Mother,Spoony {
    	public static void main(String[] args) {
    		Man m1 = new Man();
    		m1.help();
    	}
    	
    //	public void help() {
    		//System.out.println("救谁呢?");
    //		Mother.super.help(); //救母亲
    		//Spoony.super.help(); //救媳妇
    //	}
    }
    

    内部类[NEI]

    类的内部成员之五:内部类

    1.Java中允许将一个类A声明在另一个类B中,则类A就是内部类,则B称为外部类。

    2.内部类的分类:成员内部类(静态非静态) VS 局部内部类(方法内、代码块内、构造器内)
    3.成员内部类:
    一方面,作为外部类的成员:

    • 调用外部类的成员
    • 可以被static修饰
    • 可以被四种不同的权限修饰

    另一方面,作为一个类:

    • 类内可以定义属性、方法、构造器等
    • 可以被final修饰,表示此类不能被继承。不使用final,就可以被继承。
    • 可以被abstract修饰

    4.关注如下的三个问题
    4.1 如何实例化成员内部类对对象
    4.2 如何在成员内部类中区分调用外部类的结构
    4.3 开发中局部内部类的使用

    在以下代码中可以体现:

    package learning10_30;
    
    public class InnerClassTest {
    	public static void main(String[] args) {
    		//创建Dog实例(静态的成员内部类):
    		Person.Dog dog = new Person.Dog() {
    			
    		};
    		dog.show();
    		//创建Bird实例(非静态的成员内部类):
    //		Person.Bird bird = new Person.Bird() ; 错误写法
    		Person p = new  Person();
    		Person.Bird bird = p.new Bird(); //内部类属于外部类的成员,所以得先造一个外部类的对象再通过这个对象调用内部类
    										//,造内部类的对象。
    		bird.sing();
    	}
    
    }
    
    class Person{
    	String name ;
    	int age ;
    	public void eat() {
    		System.out.println("人,吃饭"); 
    	}
    	
    	//静态成员内部类
    	abstract static class Dog{
    		String name ;
    		int age ;
    		public void show() {
    			System.out.println("卡拉是条狗");
    		}
    		
    	}
    	//非静态成员内部类
    	class Bird{
    		String name ;
    		Bird(){
    			
    		}
    		public void sing() {
    			System.out.println("我是一只小小鸟");
    			eat(); //省略了 person.this.eat()
    			Person.this.eat(); //调用外部类的非静态属性 
    		}
    		
    	}
    	
    	//方法
    	public void method() {
    		//局部内部类
    		class AA{
    			
    		}
    		//局部内部类
    		class BB{
    			
    		}
    	}
    	//构造器
    	public Person(){
    		//局部内部类
    		class CC{
    			
    		}
    	}
    }
    

    异常处理[]

    异常
    .概论
    异常: 在Java语言中,将程序执行中发生的不正常情况称为“异常”
    (开发过程中的语法错误和逻辑错误不是异常)

    ●Java程序在执行过程中所发生的异常事件可分为两类:

    Error: Java虚拟机无法解决的严重问题。如: JVM系统内部错误、资源耗尽等严重情况。比如: StackOverflowError和OOM。 一般不编写针对性的代码进行处理。

    package learning10_30;
    
    public class ErrorTest {
    	
    	public static void main(String[] args) {
    		//1.栈溢出: java.lang.StackOverflowError
    		//main(args);
    		//2.堆溢出: java.lang.OutOfMemoryError
    		Integer[] arr = new Integer[1024*1024*1024];
    	}
    }
    

    Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:

    • 空指针访问
    • 试图读取不存在的文件
    • 网络连接中断
    • 数组角标越界

    2.异常体系结构

    java.lang.Throwable
    	|-----java.lang.Error:一般不编写针对性的代码进行处理。
    	|-----java.lang.Exception:可以进行异常的处理
    		|---编译时异常(checked)
    			|---IOException
    			   |---FileNotFoundException 
    		    |---ClassNotFoundException
    		|---运行时异常(unchecked)
    			|---NullPointerException
    			|---ArrayIndexOutOfBoundsException
    			|---ClassCastException 
    			|---NumberFormat Exception
    			|---InputMi smatchException
    			|---ArithmeticException
    
    

    3.从程序执行过程,看编译时异常和运行时异常

    编译时异常:执行javac. exe命名时,可能出现的异常.
    运行时异常:执行java.exe命名时,出现的异常。
    在这里插入图片描述

    4.面试题:常见的异常都有哪些?举例说明

    举例如下:

    package learning10_30;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.util.Date;
    import java.util.Scanner;
    
    import org.junit.Test;
    
    public class ExceptionTest {
    	//**************以下为编译时异常************************
    	@Test
    	public void test7() {
    		File file = new File("Hello.txt");
    		FileInputStream fis = new FileInputStream(file);
    		int data = fis.read();
    		while(data != -1) {
    			System.out.print((char)data);
    			data = fis.read();
    			
    			fis.close();
    		}
    	}
    	
    	//**************以下为运行时异常************************
    	//ArithmeticException 算数异常
    	/*@Test
    	public void test6() {
    		int a = 10 ;
    		int b = 0 ;
    		System.out.println(a/b);
    	}*/
    	
    	//InputMi smatchException  输入不匹配异常
    	/*@Test
    	public void test5() {
    		Scanner scanner =new Scanner(System.in);
    		int score = scanner.nextInt();
    		System.out.println(score);
    		scanner.close(); //关闭资源
    	}*/
    	
    	//NumberFormat Exception 数字格式异常
    	/*@Test
    	public void test4() {
    		String str = "123" ;
    		str = "abc" ;
    		int num = Integer.parseInt(str);
    	}*/
    	
    	//ClassCastException 类型转换异常
    	/*@Test
    	public void test3() {
    		Object a = new Date() ;
    		String str = (String)a ;
    	}*/
    	
    	
    	
    	//ArrayIndexOutOfBoundsException 
    	/*@Test
    	public void test2() {
    		//ArrayIndexOutOfBoundsException 
    //		int[] arr = new int[10];
    //		System.out.println(arr[10]);
    		
    		//StringIndexOutOfBoundsException
    		String str = "jklove";
    		System.out.println(str.charAt(8));
    	}*/
    	
    	
    	//NumberFormat Exception 空指针异常
    	/*	@Test
    	public void test1() {
    		
    //		int[] arr =null ;
    //		System.out.println(arr[9]);
    		
    		String str = "jklove";
    		str = null ;
    		System.out.println(str.charAt(2));
    	} */
    }
    

    异常处理

    1.Java异常处理的抓包模型

    过程一:“”:程序正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象。------并将对象抛出。--------一旦抛出对象以后,其后的代码就不再执行。
    关于异常对象的产生:
    ①系统自动生成的异常对象
    ②手动的生成一个异常对象,并抛出(throw)

    过程二:“”:可以理解为异常的处理方式:①try-catch-finally ② throws

    2.异常处理方式一:try-catch-finally

    ①try-catch-finally的使用
    try{
     	//可能出现异常的代码
     }catch(异常类型1 变量名1){
     		//处理异常的方式一
     }catch(异常类型2 变量名2){
      	   //处理异常的方式二
     }catch(异常类型3 变量名3){
      	  //处理异常的方式三
     }
      ...
     finally{
      	    //一定会执行的代码
     }
    

    说明:
    1.finally 是可选的。

    2.使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配。

    3.一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的try-catch结构(在没有写finally的情况).继续执行其后的代码。

    4.catch中的异常类如果没有子父类关系,则谁声明在上,谁声明在下无所谓。catch中的异常类型如果满足子父类的关系,则要求子类一定声明在父类的上面。否则,报错。

    5.常用的异常对象处理的方式:①String getMessage() ②printStackTrace()

    6.在try结构中声明的变量:再出了try结构以后,就不能再被调用。

    7.try-catch-finally结构可以嵌套。

    ②总结:如何看待代码中的编译时异常和运行时异常?

    体会1:使用try-catch-finally处理编译时异常,使得程序在编译时就不再报错,但是运行时仍可能报错,相当于我们使用try-catch-finally将一个编译时可能出现的异常,延时到运行时出现。

    体会2:体会2:开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。
    针对于编译时异常,我们说一定要考虑异常的处理。

    ③finally的再说明

    1.finally是可选的

    2.finally中声明的是一定会被执行的代码。即使catch中又出现异常了,try中有return语句,catch中有return语句等情况。

    3.像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。

    ④final、finally 、finalize 三者的区别

    没有什么实质性的练习,讲清他们的定义就行。
    类似的问题:

    throwthrows
    collection 和 Collections
    StringStringBufferStringBuilder
    ArrayListLinkedList
    HashMapLinkedHashMap 
    重写、重载
    
    结构不相似的:
    抽象类、接口
    ==equals()
    sleep()wait()
    

    3.异常处理方式二:throws

    ①throws
    1. "throws +异常类型"写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。
      一但当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常类型时,就会被抛出。
      异常代码后续的代码,就不再执行!
    ②对比两种处理方式
    1. try-catch-finally:真正的将异常给处理掉了。
    2. throws的方式只是将异常抛给了方法的调用者。并没有真正将异常处理掉。
    ③开发中如何选择两种处理方式
    1. 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中有异常,必须使用try- catch-finally方式处理。

    2. 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throw的方式进行处理。而执行的方法a可以考虑使用try-catch- finally方式进行处理。

    ④注意点

    方法重写的规则之一:
    子类重写的方法拋出的异常类型不大于父类被重写的方法拋出的异常类型

    4.手动抛出异常:throw

    ①throw

    在程序执行中,除了自动抛出异常对象的情况之外,我们还可以手动的throw一个异常类的对象。

    ②throw和throws的区别:

    throw表示抛出一个异常类的对象,生成异常对象的过程。声明在方法体内。
    throws 属于异常处理的一种方式,声明在方法的声明处。

    ③代码例:
    package learning11_1;
    
    public class StudentTest {
    	public static void main(String[] args) {
    		try {
    			Student s = new Student();
    			s.regist(-1001);
    			System.out.println(s);
    		} catch (Exception e) {
    //			e.printStackTrace();
    			System.out.println(e.getMessage());
    		}
    	}
    	
    }
    
    
    class Student{
    	int id ;
    	public void regist(int id) throws Exception {
    		if(id>0) {
    			this.id = id ;
    		}else {
    //			System.out.println("输入数据非法!");
    			//手动抛出异常对象
    //			throw new RuntimeException("输入数据非法!");
    			throw new Exception("数据非法");
    		}
    	}
    	@Override
    	public String toString() {
    		return "Student [id=" + id + "]";
    	}
    
    }
    

    5.用户自定义异常类

    如何自定义异常类?

    1. 继承于现有的异常结构:RuntimeException、Exception
    2. 提供全局常量:serialVersionUID
    3. 提供重载的构造器
    package learning11_1;
    
    public class MyException extends RuntimeException{
    	
    	static final long serialVersionUID = -7034897190745766939L;
    	
    	public MyException() {
    		
    	}
    	public MyException(String msg) {
    		super(msg);
    	}
    }
    

    6. 异常练习

    编写应用程序EcmDef.java,接收命令行的两个参数,要求不能输入负数,计算两数相除。
    对数据类型不一致(NumberFormatException)、缺少命令行参数(ArrayIndexOutOfBoundsException、
    除0(ArithmeticException)及输入负数(EcDef自定义的异常)进行异常处理。

    提示:
    (1)在主类(EcmDef)中定义异常方法(ecm)完成两数相除功能。
    (2)在main()方法中使用异常处理语句进行异常处理。
    (3)在程序中,自定义对应输入负数的异常类(EcDef)。
    (4)运行时接受参数java EcmDef 20 10 //args[0]=“20" args[1]=“10”
    (5)Interger类的static方法parselnt(String s)将s转换成对应的int值。
    如: int a=Interger.parselnt(“314"); //a=314;

    package learning11_1;
    
    public class EcmDef {
    	public static void main(String[] args) throws EcDef{
    		try {
    			int i = Integer.parseInt(args[0]);
    			int j = Integer.parseInt(args[1]);
    			int result = ecm(i, j);
    			System.out.println(result);
    		}catch(NumberFormatException e) {
    			System.out.println("数据类型不一致");
    		}catch(ArrayIndexOutOfBoundsException e) {
    			System.out.println("缺少命令行参数");
    		}catch(ArithmeticException e) {
    			System.out.println("除0");
    		}catch(EcDef e) {
    			System.out.println(e.getMessage());
    		}
    	}
    	
    	public static int ecm (int i ,int j) throws EcDef  {
    		if(i<0||j<0) {
    			throw new EcDef("分子或分母为负数了!");
    		}
    		return i / j ;	
    	}
    }
    

    项目三__

    IDEA__

    Ctrl + Shift + t 搜索关键字看源码

    下载地址:

    https://www.jetbrains.com/idea/download/#section=windows
    IDEA分为两个版本:旗舰版(Ultimate)和社区版(Community)。
    旗舰版收费(限30天免费试用),社区版免费,这和Eclipse很大区别。

    常用配置的设置

    快捷键的设置

    Alt + Nnt

    模板的使用

    多线程__

    程序、进程、线程

    程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。

    进程(process)是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生、存在和消亡的过程。——生命周期

    • 如:运行中的QQ,运行中的MP3播放器
    • 程序是静态的,进程是动态的
    • 进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域

    线程(thread),进程可进一步细化为线程,是一个程序内部的一条执行路 径。

    • 若一个进程同一时间并行执行多个线程,就是支持多线程的
    • 线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小
    • 一个进程中的多个线程共享相同的内存单元/内存地址空间>>它们从同一堆中分配对象,可以访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源可能就会带来安全的隐患。

    一个Java应用程序java.exe, 其实至少有三个线程: main()主线程, gc()垃圾回收线程,异常处理线程。当然如果发生异常,会影响主线程。

    并行:多个CPU同时执行多个任务。比如:多个人同时做不同的事。

    并发:一个CPU(采用时间片)同时执行多个任务。比如:多个人做同一件事。

    线程的创建与使用

    多线程的创建方式一:继承于Thread类

    1.创建一个继承于Thread类的子类
    2.重写Thread类的run()---->将此线程执行的操作声明在run()中
    3.创建Thread类的子类的对象
    4.通过此对象调用start() 作用:①启动当前线程 ②调用当前线程的run()

    例:

    package Package01;
    
    public class ThreadTest {
        public static void main(String[] args) {
            MyThread t1 = new MyThread();
    
            t1.start();
            //问题一:我们不能通过直接带调用run()的方式启动线程。
    //        t1.run();
    
            //问题二:再启动一个线程,遍历100以内的偶数。不可以还让已经start()的线程去执行。会报IllegalThreadStateException异常
    //        t1.start();
            //我们需要重新创建一个线程的对象
            MyThread t2 = new MyThread();
            t2.start();
    
    
            //如下操作仍然是在main线程中执行的
            System.out.println("hello");
            for (int i = 0; i < 100; i++) {
                if (i % 2 == 0){
                    System.out.println(Thread.currentThread().getName()+ ":"+ i+"*************maim()********");
                }
            }
        }
    }
    
    class MyThread extends Thread{
        @Override
        public void run() {
                for (int i = 0; i < 100; i++) {
                    if (i % 2 == 0){
                        System.out.println(Thread.currentThread().getName()+ ":"+ i);
                    }
            }
        }
    }
    
    练习(创建两个线程 / 创建Thread类的匿名子类)

    创建两个分线程,其中一个线程遍历100以内的偶数,另一个线程遍历100以内的奇数

    package Package.exer;
    public class ThreadDemo {
        public static void main(String[] args) {
    //        MyThread t1 = new MyThread();
    //        t1.start();
    //        MyThread t2 = new MyThread();
    //        t2.start();
            //如果只用一次,可以考虑使用匿名的方式  创建Thread类的匿名子类的方式
                new Thread(){
                    @Override
                    public void run() {
                        for (int i = 0; i < 100; i++) {
                            if (i%2!=0){
                                System.out.println(Thread.currentThread().getName()+":"+ i);
                            }
                        }
                    }
                }.start();
    
                new Thread(){
                    @Override
                    public void run() {
                        for (int i = 0; i < 100; i++) {
                            if (i%2==0){
                                System.out.println(Thread.currentThread().getName()+":"+ i);
                            }
                        }
                    }
                }.start();
        }
    }
    
    class  MyThread extends  Thread{
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if (i%2==0){
                    System.out.println(Thread.currentThread().getName()+":"+ i);
                }
            }
        }
    }
    
    class MyThread2 extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if (i%2!=0){
                    System.out.println(Thread.currentThread().getName()+":"+ i);
                }
            }
    
        }
    }
    
    线程的常用方法
    1. start(): 启动当前线程;调用当前线程的run()
    2. run(): 通常需要重写Thread类中的此方法,(将创建的线程要执行的操作声明在此方法中)
    3. currentThread(): 静态方法,返回执行当前代码的线程
    4. getName(): 获取当前线程的名字
    5. setName(): 设置当前线程的名字
    6. yield():释放当前cpu的执行权
    7. join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态。
    8. stop(): 已过时。当执行此方法时,强制结束当前线程。
    9. sleep(long millitime): 让当前线程“睡眠”指定的millitime毫秒。在指定的millitime 亳秒时间内,当前线程是阻塞状态。
    10. isAlive(): 判断当前线程是否存活

    例:

    package Package.java;
    public class ThreadMethonTest {
        public static void main(String[] args) {
            HelloThread h1 = new HelloThread("Thread:101");
    //        h1.setName("线程一");
            h1.start();
            //给主线程命名
            Thread.currentThread().setName("主线程");
            for (int i = 0; i < 100; i++) {
                if (i%2==0){
                    System.out.println(Thread.currentThread().getName()+":"+i);
                }
    
                if (i==20){
                    try {
                        h1.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            System.out.println(h1.isAlive());
        }
    }
    
    class HelloThread extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if (i%2==0){
                    try {
                        sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":"+i);
                }
    
                if (i%20==0){
                    yield();
                }
            }
        }
        public HelloThread(String name){
            super(name);
        }
    }
    
    线程优先级

    1
    MAX_PRIORITY:10
    MIN_PRIORITY:1
    NORM_PRIORITY:5 -->默认优先级

    2.如何获取和设置当前线程的优先级:
    getPriority():获取线程的优先级
    setPriority(int p):设置线程的优先级

    说明:高优先级的线程要抢占低优先级线程cpu的执行权。但是只是从概率上讲,高优先级的线程高概率的情况下被执行。并不意味着只有当高优先级的线程执行完以后,低优先级的线程才执行。

    多线程的创建方式二:实现Runnable接口

    1. 创建一个实现了Runnable接口的类
    2. 实现类去实现Runnable中的抽象方法: run()
    3. 创建实现类的对象
    4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
    5. 通过Thread类的对象 调用start()

    例子:

    package November11_3;
    public class WindowTest1 {
        public static void main(String[] args) {
            Windows1 windows1 = new Windows1();
            Thread t1 = new Thread(windows1);
            t1.setName("一号窗口:");
            t1.start();
            Thread t2 =new Thread(windows1);
            t2.setName("二号窗口:");
            t2.start();
            Thread t3 = new Thread(windows1);
            t3.setName("三号窗口:");
            t3.start();
        }
    }
    
    class Windows1 implements Runnable{
        private int ticket = 100 ;
        @Override
        public void run() {
            while (true){
                if (ticket>0){
                    System.out.println(Thread.currentThread().getName()+"卖票咯,还剩票号"+ticket);
                    ticket--;
                }else {
                    break;
                }
            }
        }
    }
    
    

    比较创建线程的两种方式

    开发中:优先选择:实现Runnable接 口的方式
    原因:
    1.实现的方式没有类的单继承性的局限性
    2.实现的方式更适合来处理多个线程有共享数据的情况。

    联系: public class Thread implements Runnable
    相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中。

    线程的生命周期

    在这里插入图片描述

    线程的同步

    在Java中,我们通过同步机制,来解决线程的安全问题。

    方式一:同步代码块

     synchronized(同步监视器){
     *              //  需要被同步的代码
     *             //   1.操作共享数据的代码,即为需要被同步的代码 -->不能包含代码多了, 也不能包含代码少了。
     *            //    2.共享数据:多个线程共同操作的变量。   比如:ticket就是共享数据。
     *           //     3.同步监视器,俗称:锁。 任何一个类的对象,都可以充当锁。
     *              //      要求:多个线程必须要共用同一把锁。
     *             //       补充:在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器。
     *          }
    

    方式二:同步方法

    如果操作共享数据的代码完整的声明在一个方法中, 我们不妨将此方法声明同步的。

    关于同步方法的总结:
    1.同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。
    2.非静态的同步方法,同步监视器是: this
    静态的同步方法,同步监视器是:当前类本身

    使用同步机制将单例模式中的懒汉式改写为线程安全的

    package November11_3;
    public class BankTest {
    
    }
    
    class Bank{
        private Bank(){ }
    
        private static Bank instance = null ;
    
        public static Bank getInstance(){
            //方式一:效率稍差
    //        synchronized (Bank.class) {
    //            if (instance == null){
    //                instance = new Bank();
    //            }
    //            return instance;
    //        }
            //方式二:效率更高
            if (instance == null){
                synchronized (Bank.class) {
                    if (instance == null){
                        instance = new Bank();
                    }
                }
            }
            return instance;
        }
    }
    

    线程的死锁问题

    死锁
    不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。
    出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续。
    解决方法
    专门的算法、原则
    尽量减少同步资源的定义
    尽量避免嵌套同步

    方式三:Lock锁 —JDK5.0新增

    线程的通讯

    线程通讯的例子:使用两个线程打印 1-100.线程1,线程2 交替打印

    涉及到的三个方法:

    • wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
    • notify(): 一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被 wait,就唤醒优先级高的
    • notifyAll(): 一旦执行此方法,就会唤醒所有被wait的线程。

    说明:

    1. wait(),notify(),notifyAll()三个方法必须使用同步代码块或同步方法中。
    2. wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。
      否则,会出现IlLegaLMonitorStateException异常
    3. wait(),notify(),notifyAll()三个方法是定于在java.lang.Object类中的。
    class Number implements Runnable{
        private int number =1 ;
        @Override
        public void run() {
            while (true){
    
                synchronized (this) {
    
                    notifyAll();
    
                    if (number<=100){
    
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                        System.out.println(Thread.currentThread().getName()+":"+number);
                        number++;
    
                        try {
                            //使得调用如下wait()方法的线程进入阻塞状态
                            wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                    }else {
                        break;
                    }
                }
    
            }
        }
    }
    
    public class CommunicationTest {
        public static void main(String[] args) {
            Number n1 = new Number();
            Thread t1 = new Thread(n1);
            Thread t2 = new Thread(n1);
            t1.setName("线程一");
            t2.setName("线程二");
            t1.start();
            t2.start();
        }
    }
    
    

    sleep()和wait() 的异同?

    1.相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态。
    2.不同点:
    (1)两个方法声明的位置不同:Thread类中声明sleep(),Object类中声明wait()。
    (2)调用的要求不同: sleep( )可以在任何需要的场景下调用。wait( )必须使用在同步代码块或同步方法中
    (3)关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()释放锁。

    JDK5.0新增线程创建方式

    新增方式一:实现Callable接口
    与使用Runnable相比,Callable功能更强大些

    • call()可以有返回值
    • call()可以抛出异常,被外面的操作捕获,获取异常的信息
    • Callable支持泛型的返回值

    新增方式二:使用线程池

    好处:
    1.提高响应速度(减少了创建新线程的时间)
    2.降低资源消耗(重复利用线程池中线程,不需要每次都创建)
    3.便于线程管理

    corePoolSize:核心池的大小
    maximumPoolSize:最大线程数
    keepAliveTime:线程没有任务时最多保持多长时间后会终止

    面试题:创建多线程有几种方式? 答:四种!

    常用类__[CHANG]

    String:字符串,使用一对" "引起来表示。

    1. String声明为final的,不可被继承

    2. String实现了Serializable接口:表示字符事是支持序列化的。
      实现了Comparable接口:表示String可以比较大小

    3. String内部定义了final char[] value用于存储字符串数据

    4. String:代表不可变的字符序列。简称:不可变性。
      体现: ①当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值
      ②当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
      ③当调用String 的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。

    5. 通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。

    6. 字符串常量池中是不会存储相同内容的字符串的。

    String的实例化方式

    方式一:通过字面量定义的方式
    方式二:通过new +枸造器的方式

    通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。

    String s1 = "javaEE" ;
    String s2 =  "javaEE" ;
    

    通过new +构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。

    String s3 = new  String("javaEE");
    String s4 = new String("javaEE");
    
    System.out.println(s1 == s2); //true
    System.out.println(s1 == s3); //fasle
    System.out.println(s1 == s4); //fasle
    System.out.println(s3 == s4); //fasle
    

    面试题: String s = new String(“abc”);方式创建对象,在内存中创建了几个对象?
    答:两个 ,一个是堆空间中new结构,另一个是char[]对应的常量池中的数据: “abc”

    String不同拼接操作的对比

    在这里插入图片描述
    结论:

    1. 常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
    2. 只要其中有一个是变量,结果就在
    3. 如果拼接的结果调用intern()方法,返回值就在常量池中

    String常用方法

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    String与基本数据类型转换

    String --> 基本数据类型 调用parseint(String s)方法

    @Test
        public void test1(){
            String s1 = "666" ;
            int i1 = Integer.parseInt(s1);
            System.out.println(i1);
    
            String s2 = String.valueOf(i1);
            String s3 = s2 + "";
    
        }
    

    基本数据类型 --> String 调用String类的 valueOf(int n) 方法
    或者 + “”

    String 与 字符数组转换

    String 与 char[] 之间的转换

    String --> char[]: 调用String的toCharArray()
    char[] --> String: 调用String的构造器

    @Test
        public void test2(){
            String str1 = "abc123" ;
            char[] c1 = str1.toCharArray();  //String类的 toCharArray()方法可将字符串变为字符数组
            for (int i = 0; i < c1.length; i++) {
                System.out.println(c1[i]);
    
            }
    
            char[] c2 = new char[]{'Y','u','Z','a','i'};
            String str2 = new String(c2);
            System.out.println(str2);
        }
    
    String 与 byte[ ] 之间的转换

    编码 String --> byte[]: 调用String的getBytes() ; 字符串 --> 字节
    解码 byte --> String ; 字节 --> 字符串
    解码时,解码集与编码集需要一致,不然会出现乱码。

    @Test
        public void test3() throws UnsupportedEncodingException {
            String str1 = "yuzai123" ;
            byte[] b1 = str1.getBytes();
            System.out.println(Arrays.toString(b1)); // 将数组转换成String类型输出, 若直接输出b1,输出的是地址值
    
            byte[] gbk1 = str1.getBytes("gbk"); // 使用gbk字符集进行编码
            System.out.println(Arrays.toString(gbk1));
    
            System.out.println("***************** ");
            String str2 = new String(b1);
            System.out.println(str2);
    
            String str3 = new String(gbk1);
            System.out.println(str3);
        }
    

    String、StringBuffer、 StringBuilder三者的异同?

    String: 不可变的字符序列 ;底层使用char[]存储

    StringBuffer: 可变的字符序列;线程安全的,效率低;底层使用char[]存储

    StringBuilder: 可变的字符序列 ;jdk5.0新增的,线程不安全的,效率高;底层使用char[]存储

    StringBuffer 常用方法

    在这里插入图片描述
    在这里插入图片描述

    总结:增删改查插长度遍历

    对比String、StringBuffer、StringBuilder三者的效率:

    从高到低排列:StringBuilder > StringBuffer > String

    JDK8之前日期时间API

    1. java.lang.System类
     @Test
        public void test1(){
            long time = System.currentTimeMillis(); //返回当前时间1970年1月1日0时日分日秒之间以毫秒为单位的时间差。(称为时间戳)
            System.out.println(time);
        }
    
    2. java.util.Date类

    java.util.Date类
    –构造器1 Date() 创建一个对应当前时间的Date对象
    –构造器2 Date(long date) 创建指定毫秒数的Date对象
    方法1:toString() 显示当前的年月日时分秒
    方法2: getTime() 获取当前Date对象对应的毫秒数 (时间戳)

    Date time2 = new Date(1937306108410L);
            System.out.println(time2.toString());
    
            //java.sql.Date类
            java.sql.Date date1 = new  java.sql.Date(12387484514874l);     // 创建java.sql.Date对象
            System.out.println(date1);  //2362-07-18
    
                 // 将java.util.Date对象转换为java.sql.Date 情况一
            Date date2 = new java.sql.Date(455874184544l);
            java.sql.Date date3 = (java.sql.Date) date2 ;  // 将date2强转为java.sql.Date类 (多态)
    
                // 将java.util.Date对象转换为java.sql.Date 情况二
            Date time0 = new Date(123456789L);
            java.sql.Date date4 = new java.sql.Date(time0.getTime()) ;  //  (利用时间戳的共性)
    
    java.sql.Date类

    java.sql.Date类 对应着数据库中的日期类型的变量
    > 如何实例化
    > java.util.Date对象转换为java.sql.Date 对象

    //java.sql.Date类
            java.sql.Date date1 = new  java.sql.Date(12387484514874l);     // 创建java.sql.Date对象
            System.out.println(date1);  //2362-07-18
    
                 // 将java.util.Date对象转换为java.sql.Date 情况一
            Date date2 = new java.sql.Date(455874184544l);
            java.sql.Date date3 = (java.sql.Date) date2 ;  // 将date2强转为java.sql.Date类 (多态)
    
                // 将java.util.Date对象转换为java.sql.Date 情况二
            Date time0 = new Date(123456789L);
            java.sql.Date date4 = new java.sql.Date(time0.getTime()) ;  //  (利用时间戳的共性)
    
    展开全文
    m0_56265851 2021-11-22 20:01:06
  • 注:该项目来源于b站视频Python爬虫编程基础5天速成(2021全新合集)Python入门+数据分析,python语法基础不在本文章中。 python爬虫 1.任务介绍 使用任务驱动型学习方法。任务为爬取电影信息。 需求 爬取豆瓣电影...

    前言

    注:该项目来源于b站视频Python爬虫编程基础5天速成(2021全新合集)Python入门+数据分析,python语法基础不在本文章中。

    python爬虫

    1.任务介绍

    使用任务驱动型学习方法。任务为爬取电影信息。

    需求

    爬取豆瓣电影TOP250的基本信息,包括:
    电影名称、豆瓣评分、评价数、电影概述、电影链接等。

    2.爬虫初识

    在这里插入图片描述
    很多网站其实是用的爬虫爬的别的网站的信息,处理后放到数据库里,然后通过自己的前端页面将数据展示出来,通过广告、会员等形式进行流量变现实现盈利。如搜索引擎百度,天眼查,AGE动漫网等等。
    搜索引擎原理:
    在这里插入图片描述

    3.基本流程

    在这里插入图片描述

    3.1准备工作

    在这里插入图片描述
    每次发出url请求,其实不是简简单单的就一个网址,还有一些请求头信息,如果要模拟浏览器发出请求,也要带上相应的请求头信息:
    在这里插入图片描述
    比如想爬取一些登陆后才能看的东西,就一定要记录请求头中的cookie,访问url不带cookie服务器会认为你没有登陆。

    3.1.1分析页面

    浏览器页面-右键-检查,在elements下看看数据位置
    发现在ol,li列表标签内存在每部电影的数据:
    在这里插入图片描述

    3.1.2编码规范

    在这里插入图片描述
    hello.py:

    #-*- coding = utf-8 -*-
    #@Time : 2021/7/19 15:22
    #@Author : coderhao
    #@File : helloword.py
    #@Software : PyCharm
    
    
    # 注释
    print("hello world")
    

    使用右键运行:
    在这里插入图片描述
    spider.py:

    #-*- coding = utf-8 -*-
    #@Time : 2021/7/19 16:49
    #@Author : coderhao
    #@File : spider.py
    #@Software : PyCharm
    
    # 定义一个函数
    def main():
        print("hello")
    
    
    # 程序执行开始的地方
    # 明明像hello.py那样右键就能运行,为什么要这样多此一举呢?
    # 因为代码是顺序执行的,可能会出现一些顺序上的问题,因此使用下面的写法,我们来调配函数的调用顺序
    # 这样更清楚的明白代码逻辑
    if __name__=="__main__":
        # 调用函数
        main()
    
    

    3.1.3引入模块

    在这里插入图片描述
    本项目要用的模块:

    # 网页解析,获取数据
    from bs4 import BeautifulSoup
    # 正则表达式,文字匹配
    import re
    # 制定url,获取网页数据
    import urllib.request,urllib.error
    # 进行excel操作
    import xlwt
    # 进行sqlite数据库操作
    import sqlite3
    

    在引入的时候,很可能报错,说这模块没有,需要先安装上:
    在这里插入图片描述
    在这里插入图片描述

    3.1.4完善pachong.py-构建整个流程

    pachong.py:

    #-*- coding = utf-8 -*-
    #@Time : 2021/7/19 17:18
    #@Author : coderhao
    #@File : pachong.py
    #@Software : PyCharm
    
    # 网页解析,获取数据
    from bs4 import BeautifulSoup
    # 正则表达式,文字匹配
    import re
    # 制定url,获取网页数据
    import urllib.request,urllib.error
    # 进行excel操作
    import xlwt
    # 进行sqlite数据库操作
    import sqlite3
    
    def main():
        # 访问url
        baseurl="https://movie.douban.com/top250?start="
        # 保存路径
        savepath=".\\doubanTop250.xls"
        # 1.爬取网页
        datalist=getData(baseurl)
        # 3.保存数据
        saveData(savepath)
    
    # 1.爬取网页
    def getData(baseurl):
        datalist=[]
        return datalist
        # 2.解析数据
        # 第一步网页爬取是个循环过程,所以,解析过程也是跟在爬到的每个网页后面的,更恰当地说这一步应该是在第一步内部
    
    
    # 3.保存数据
    def saveData(savepath):
        print("todo---save")
    
    if __name__ == '__main__':
        main()
    

    3.2获取数据

    在这里插入图片描述
    注:python3整合了urllib和urllib2,现在使用urllib就行了

    3.2.1介绍urllib

    这里用到了一个专门用来简单进行各种网络响应的网站http://httpbin.org/
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    #-*- coding = utf-8 -*-
    #@Time : 2021/7/19 20:59
    #@Author : coderhao
    #@File : testUrllib.py
    #@Software : PyCharm
    
    import urllib.request
    
    # 获取一个get请求
    response=urllib.request.urlopen("https://www.baidu.com")
    # 返回:<http.client.HTTPResponse object at 0x00000163774C03A0>
    print(response)
    '''
    返回:
    <html>
    <head>
    	<script>
    		location.replace(location.href.replace("https://","http://"));
    	</script>
    </head>
    <body>
    	<noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>
    </body>
    </html>
    '''
    # .read()会默认以二进制方式读取,然后decode('utf-8')会以utf-8的形式解析
    # 如果上面url是http这种不带s的不安全方式,打印出的代码会多很多,包含很多其他的东西
    print(response.read().decode('utf-8'))
    
    
    # 获取post请求
    # urllib.parse:解析器,将需要模拟post请求发送的键值对按一定格式解析变成二进制然后放到bytes()里
    import urllib.parse
    # 需要发送的数据变成bytes格式
    data=bytes(urllib.parse.urlencode({"hello":"world"}),encoding="utf-8")
    response=urllib.request.urlopen("http://httpbin.org/post",data=data)
    '''
    返回:
    {
      "args": {}, 
      "data": "", 
      "files": {}, 
      "form": {
        "hello": "world"
      }, 
      "headers": {
        "Accept-Encoding": "identity", 
        "Content-Length": "11", 
        "Content-Type": "application/x-www-form-urlencoded", 
        "Host": "httpbin.org", 
        "User-Agent": "Python-urllib/3.9", 
        "X-Amzn-Trace-Id": "Root=1-60f57d96-0d74843b2d2dd55b1669e7cf"
      }, 
      "json": null, 
      "origin": "111.17.194.90", 
      "url": "http://httpbin.org/post"
    }
    '''
    # 返回的数据和在httpbin.org上看到的一致
    print(response.read().decode('utf-8'))
    
    # 使用get请求测试超时情况
    # 正常时
    response=urllib.request.urlopen("http://httpbin.org/get")
    '''
    返回:
    {
      "args": {}, 
      "headers": {
        "Accept-Encoding": "identity", 
        "Host": "httpbin.org", 
        "User-Agent": "Python-urllib/3.9", 
        "X-Amzn-Trace-Id": "Root=1-60f580e9-110d8eb460884b5a3e13eb7e"
      }, 
      "origin": "111.17.194.90", 
      "url": "http://httpbin.org/get"
    }
    '''
    # 通过返回数据中的  "User-Agent":"Python-urllib/3.9" 可以发现服务器察觉到了我们是python程序,即爬虫,而不是真正的浏览器
    # 在访问反爬虫的服务器时需要进行伪装,不然极有可能ip锁定无法访问
    print(response.read().decode('utf-8'))
    
    # 超时
    request=urllib.request.urlopen("http://httpbin.org/get",timeout=0.01)
    # 超时报错误: urllib.error.URLError: <urlopen error timed out>
    print(request.read().decode('utf-8'))
    
    # 所以防止超时异常这种情况需要捕捉异常
    # 正常情况下,由于url失效、网络不畅、服务器繁忙、服务器拒绝等等情况导致访问长时间无应答是很普遍的,因此捕获异常,放过去,之后再返回来针对性的爬才是正确的方式
    try:
        response = urllib.request.urlopen("http://httpbin.org/get", timeout=0.01)
        print(response.read().decode('utf-8'))
    except urllib.error.URLError as e:
        print("time out!")
    
    response = urllib.request.urlopen("http://httpbin.org/get")
    # 状态码:200
    # 尝试爬豆瓣网发现返回为错误代码418,意思是服务器发现是个爬虫
    print(response.status)
    # 得到响应头信息,一个数组
    print(response.getheaders())
    # 得到某个特定的响应头信息
    print(response.getheader("Date"))
    
    # 对于爬虫程序伪装的问题,前面的请求方式和浏览器最大的区别就是前面的方式只发url,而浏览器除了发url还发一些头信息
    # headers里放伪装信息,F12-Network-All-Headers-Request Headers里面的都可以放
    # 这里headers里放入了最重要的User-Agent,用户代理,表示我们是个xxx规格的浏览器,
    url ="http://httpbin.org/post"
    data=bytes(urllib.parse.urlencode({"hello":"world"}),encoding="utf-8")
    headers={
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3872.400 QQBrowser/10.8.4455.400"
    }
    request=urllib.request.Request(url,data=data,headers=headers,method="POST")
    response=urllib.request.urlopen(request)
    '''
    返回:
    {
      "args": {}, 
      "data": "", 
      "files": {}, 
      "form": {
        "hello": "world"
      }, 
      "headers": {
        "Accept-Encoding": "identity", 
        "Content-Length": "11", 
        "Content-Type": "application/x-www-form-urlencoded", 
        "Host": "httpbin.org", 
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3872.400 QQBrowser/10.8.4455.400", 
        "X-Amzn-Trace-Id": "Root=1-60f58c8b-4e8c004a2cdca535024c38ed"
      }, 
      "json": null, 
      "origin": "111.17.194.90", 
      "url": "http://httpbin.org/post"
    }
    '''
    # 这里返回的响应头中的User-Agent就是浏览器信息了,服务器没识别到爬虫
    print(response.read().decode('utf-8'))
    
    
    # get方式请求豆瓣网试试
    url ="https://www.douban.com"
    headers={
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3872.400 QQBrowser/10.8.4455.400"
    }
    request=urllib.request.Request(url,headers=headers)
    response=urllib.request.urlopen(request)
    # 得到了豆瓣的相应信息,由于信息太多,这里不再用多行注释展开
    print(response.read().decode('utf-8'))
    

    3.2.2完善pachong.py-获取数据

    有了3.2.1中对urllib的使用,我们就可以对pachong.py中获取数据部分进行完善。
    pachong.py(main方法完善了爬取网页;其他方法添加了一个爬取特定url的小方法):

    #-*- coding = utf-8 -*-
    #@Time : 2021/7/19 17:18
    #@Author : coderhao
    #@File : pachong.py
    #@Software : PyCharm
    
    # 网页解析,获取数据
    from bs4 import BeautifulSoup
    # 正则表达式,文字匹配
    import re
    # 制定url,获取网页数据
    import urllib.request,urllib.error
    # 进行excel操作
    import xlwt
    # 进行sqlite数据库操作
    import sqlite3
    
    def main():
        # 访问url
        baseurl="https://movie.douban.com/top250?start="
        # 保存路径
        savepath=".\\doubanTop250.xls"
        # 1.爬取网页
        datalist=getData(baseurl)
        # 3.保存数据
        saveData(savepath)
    
        askURL(baseurl)
    
    # 1.爬取网页
    def getData(baseurl):
        datalist=[]
        # 通过循环得到所有的url
        # range函数左闭右开
        for i in range(0,10):
            url=baseurl+str(i*25)
            html=askURL(url)
            # 2.解析数据
            # 第一步网页爬取是个循环过程,所以,解析过程也是跟在爬到的每个网页后面的,更恰当地说这一步应该是在第一步内部
    
            # 将html解析后的信息加入到datalist中
            datalist.append()
        return datalist
    
    
    
    # 3.保存数据
    def saveData(savepath):
        print("todo---save")
    
    # 其他单独方法
    
    # 得到一个指定url内容的方法
    def askURL(url):
    	html=""
        # 模拟浏览器请求头信息
        head={
            # 用户代理,告诉服务器我们是什么类型的机器/浏览器,本质是告诉服务器我们能接收什么水平的文件
            # 从浏览器F12里复制时请尽量让该信息在一行里显示再赋值,不然复制过来也是多行而且数据中间有很多空格,有可能出问题
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3870.400 QQBrowser/10.8.4405.400"
        }
        # 模拟的总请求信息
        request = urllib.request.Request(url, headers=head)
        try:
            response = urllib.request.urlopen(request)
            html = response.read().decode("utf-8")
            # 可以输出测试
            # print(html)
        except urllib.error.URLError as e:
            # 如果e有code,打印code
            if hasattr(e,"code"):
                print(e.code)
            # 如果e有reason,打印reason
            if hasattr(e,"reason"):
                print(e.reason)
    
    	return html
    
    
    
    
    
    if __name__ == '__main__':
        main()
    

    3.3解析内容

    在这里插入图片描述

    3.3.1BeautifulSoup的使用

    首先需要一个html网页作为测试对象,打开baidu,ctrl+s保存为html文件,放到和testBs4.py并列的位置,更名为baidu,调格式可以ctrl+alt+L。
    这里做测试的网页样子:
    在这里插入图片描述
    目录结构:
    在这里插入图片描述
    testBs4.py:

    #-*- coding = utf-8 -*-
    #@Time : 2021/7/20 9:58
    #@Author : coderhao
    #@File : testBs4.py
    #@Software : PyCharm
    
    '''
    BeautifulSoup4将复杂HTML文档转换成一个复杂的树形结构,每个节点都是python对象,所有对象可以归纳为四种:
    - Tag 标签及其内容
    - NavigableString 标签内部内容,就是字符串
    - BeautifulSoup
    - Comment
    '''
    
    from bs4 import BeautifulSoup
    
    # 打开文件路径
    file=open("./baidu.html","rb")
    # 文件读到内存中
    html=file.read()
    # 参数表示(解析哪个内容,使用BeautifulSoup中解析什么文件格式的解析器),这里参数为(html,"html.parser")。
    bs=BeautifulSoup(html,"html.parser")
    
    # <title>百度一下,你就知道</title>
    # 抽取的就是baidu.html中的title标签
    # 再说的直接一点,bs.xx,抽取的就是html中第一个xx标签的内容(带标签)
    print(bs.title)
    # <class 'bs4.element.Tag'>
    print(type(bs.title))
    
    # 不带标签,只要内容
    # 如果内容带有注释,则type(bs.title.string)是bs4.element.Comment格式,print会输出不包含注释符号的字符串
    # 百度一下,你就知道
    print(bs.title.string)
    # <class 'bs4.element.NavigableString'>
    print(type(bs.title.string))
    
    # 获取某一标签的所有属性,返回一个字典
    # {'href': 'http://news.baidu.com', 'target': '_blank', 'class': ['mnav', 'c-font-normal', 'c-color-t']}
    print(bs.a.attrs)
    # <class 'dict'>
    print(type(bs.a.attrs))
    
    # 整个文档
    print(bs)
    # <class 'bs4.BeautifulSoup'>
    print(type(bs))
    
    
    #————————————————————————————————————————————————————
    # 以上为基本用法,但用起来效率太低,下面说怎么应用
    
    # 一、文档的遍历(不常用):将文档中相似的东西遍历出来
    # 详细的遍历文档树网址:https://blog.csdn.net/chinaltx/article/details/86748763
    # 其中如下:
    # 得到head标签内部的所有内容,以列表形式得到
    print(bs.head.contents)
    # 列表中下标为1的元素
    print(bs.head.contents[1])
    
    # 二、文档的搜索(常用):有针对性的根据结构取出数据
    # 1.find_all()搜索符合特定条件的所有标签,以列表方式返回
    # 1.1查找所有a标签的内容,以列表形式返回
    t_list=bs.find_all("a")
    # 1.2正则表达式搜索,使用search()方法来匹配内容
    # 例:查找标签中含有a字符的内容,以列表形式返回
    import re
    t_list=bs.find_all(re.compile("a"))
    # 1.3传入一个函数/方法,根据函数的要求来搜索
    # 方法:传入一个标签,判断标签里面是否存在name属性
    def name_is_exists(tag):
        return tag.has_attr("name")
    # 查找标签中含有name属性的内容,以列表形式返回
    t_list=bs.find_all(name_is_exists)
    # 以循环方式输出查看
    # for item in t_list:
    #     print("---------------------------------------------")
    #     print(item)
    # 2.kwargs 参数搜索
    # 搜索标签属性符合规则的标签内容
    t_list=bs.find_all(id="head")
    # 搜索存在某个标签属性的标签
    t_list=bs.find_all(class_=True)
    # 3.text参数
    '''
    ---------------------------------------------
    新闻
    ---------------------------------------------
    地图
    ---------------------------------------------
    直播
    ---------------------------------------------
    地图
    '''
    # 搜索标签内容,条件是text中内容=标签内容
    t_list=bs.find_all(text=["新闻","地图","直播"])
    # 看起来这个搜索好像在做无用功,我知道标签内容还用你搜?但其实是可以配合正则表达式来搜索含有某些特性的标签内容的
    # 搜索含有数字的标签内容
    t_list=bs.find_all(text=re.compile("\d"))
    
    # 4.limit参数
    # 限制搜索的数量
    t_list=bs.find_all("a",limit=3)
    
    # 5.css选择器
    # 通过标签查找
    t_list=bs.select("title")
    # 通过标签里面的属性查找
    t_list=bs.select("a[class='share-icons-tqq']")
    # 通过类名查找:.xxx表示类名
    t_list=bs.select(".mnav")
    # 通过id查找:#xx表示id
    t_list=bs.select("#u1")
    # t_list拿到文本的方式
    print(t_list[0].get_text())
    
    

    3.3.2正则表达式的补充

    在这里插入图片描述
    在这里插入图片描述
    以上是正则表达式的规范模板,在不同的语言中有不同的解决正则表达式匹配的库。
    比如python中就是re库:
    在这里插入图片描述
    还有一些模式设置:
    在这里插入图片描述
    testRe.py:

    #-*- coding = utf-8 -*-
    #@Time : 2021/7/21 10:26
    #@Author : coderhao
    #@File : testRe.py
    #@Software : PyCharm
    
    
    
    # 正则表达式:字符串模式(判断字符串是否符合一定的标准)
    # 引入re
    import re
    
    # 1.有模式对象
    # 创建模式对象
    # 此处的AA是正则表达式,用来验证其它字符串
    pat=re.compile(".*a")
    # 验证字符串bra是否符合.*a
    # <re.Match object; span=(0, 3), match='bra'> :在0-2下标序列的位置匹配到(左闭右开)
    m=pat.search("bra")
    print(m)
    # 结果为None,未匹配上
    m=pat.search("bed")
    print(m)
    
    # 2.没有模式对象,简写,前面是模板,后面是被校验对象
    m=re.search(".*a","bed")
    print(m)
    
    # 找到所有符合的然后以列表形式返回
    m=re.findall("a","sajlkfjaf")
    # ['a', 'a']
    print(m)
    
    
    m=re.findall("[A-Z]","ADASasoJKLlajdaS")
    # ['A', 'D', 'A', 'S', 'J', 'K', 'L', 'S']
    print(m)
    
    m=re.findall("[A-Z]+","ADASasoJKLlajdaS")
    # ['ADAS', 'JKL', 'S']
    print(m)
    
    # sub,替换作用
    # 将"a;ljfds;fsaj"中所有a替换为A
    m=re.sub("a","A","a;ljfds;fsaj")
    print(m)
    
    # 建议在正则表达式中,被比较的字符串前面加上r,防止转义字符干扰
    str="\adsjalkd\'ad"
    # dsjalkd'ad
    print(str)
    str=r"\adsjalkd\'ad"
    # \adsjalkd\'ad
    print(str)
    

    3.3.3完善pachong.py-正则提取

    对每次遍历得到的html进行正则提取。
    在这里插入图片描述

    pachong.py:

    # -*- coding = utf-8 -*-
    # @Time : 2021/7/19 17:18
    # @Author : coderhao
    # @File : pachong.py
    # @Software : PyCharm
    
    # 网页解析,获取数据
    from bs4 import BeautifulSoup
    # 正则表达式,文字匹配
    import re
    # 制定url,获取网页数据
    import urllib.request, urllib.error
    # 进行excel操作
    import xlwt
    # 进行sqlite数据库操作
    import sqlite3
    
    
    def main():
        # 访问url
        baseurl = "https://movie.douban.com/top250?start="
        # 保存路径
        savepath = ".\\doubanTop250.xls"
        # 1.爬取网页
        datalist = getData(baseurl)
        # 3.保存数据
        saveData(savepath)
    
    
    # 全局变量
    # re.compile()创建正则规则
    '''
    对照规则:
    <div class="item">
    <div class="pic">
    <em class="">1</em>
    <a href="https://movie.douban.com/subject/1292052/">
    <img alt="肖申克的救赎" class="" src="https://img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg" width="100"/>
    </a>
    </div>
    <div class="info">
    <div class="hd">
    <a class="" href="https://movie.douban.com/subject/1292052/">
    <span class="title">肖申克的救赎</span>
    <span class="title"> / The Shawshank Redemption</span>
    <span class="other"> / 月黑高飞(港)  /  刺激1995(台)</span>
    </a>
    <span class="playable">[可播放]</span>
    </div>
    <div class="bd">
    <p class="">
                                导演: 弗兰克·德拉邦特 Frank Darabont   主演: 蒂姆·罗宾斯 Tim Robbins /...<br/>
                                1994 / 美国 / 犯罪 剧情
                            </p>
    <div class="star">
    <span class="rating5-t"></span>
    <span class="rating_num" property="v:average">9.7</span>
    <span content="10.0" property="v:best"></span>
    <span>2399691人评价</span>
    </div>
    <p class="quote">
    <span class="inq">希望让人自由。</span>
    </p>
    </div>
    </div>
    </div>
    '''
    findlink = re.compile(r'a href="(.*?)">')
    # re.S忽略换行符
    # findImgSrc=re.compile(r'<img.*src="(.*?)" width="100"/>',re.S)
    findImgSrc = re.compile(r'<img alt=".*" class="" src="(.*?)" width="100"/>', re.S)
    findTitle = re.compile(r'<span class="title">(.*?)</span>')
    findRating = re.compile(r'<span class="rating_num" property="v:average">(.*?)</span>')
    findJudge = re.compile(r'<span>(\d*?)人评价</span>')
    findInq = re.compile(r'<span class="inq">(.*?)</span>')
    findBd = re.compile(r'<p class="">(.*?)</p>', re.S)
    
    
    # 1.爬取网页
    def getData(baseurl):
        datalist = []
        # 通过循环得到所有的url
        # range函数左闭右开
        for i in range(0, 10):
            url = baseurl + str(i * 25)
            html = askURL(url)
            # 2.解析数据
            # 第一步网页爬取是个循环过程,所以,解析过程也是跟在爬到的每个网页后面的,更恰当地说这一步应该是在第一步内部
            # 解析器选择,并解析
            soup = BeautifulSoup(html, "html.parser")
            # 遍历符合要求的字符串,形成列表。需要的是<div class="info">的内部内容
    
            for item in soup.find_all("div", class_="item"):
                # item存的一个电影的信息
                # print(item)
                # 用来保存一部电影的所有信息
                data = []
                item = str(item)
    
                # 影片详情链接
                link = re.findall(findlink, item)[0]
                print("link:" + link)
                data.append(link)
    
                # 影片图片url
                imgSrc = re.findall(findImgSrc, item)[0]
                print("imgSrc:" + imgSrc)
                data.append(imgSrc)
    
                # 影片题目
                title = re.findall(findTitle, item)
                if (len(title) == 2):
                    # 中文名
                    ctitle = title[0]
                    # 外文名
                    otitle = title[1].replace("/", "")  # 去掉/
                    data.append(ctitle)
                    data.append(otitle)
                else:
                    data.append(title[0])
                    data.append(' ')  # 留空
                print("ctitle:" + ctitle + "otitle:" + otitle)
    
                # 影片评分
                rating = re.findall(findRating, item)[0]
                print("rating:" + rating)
                data.append(rating)
    
                # 评分人数
                judge = re.findall(findJudge, item)[0]
                print("judge:" + judge)
                data.append(judge)
    
                # 影片简述
                inq = re.findall(findInq, item)
                if (len(inq) != 0):
                    inq = inq[0].replace("。", "")
                    data.append(inq)
                else:
                    data.append(" ")
                    inq = " "
                print("inq:" + inq)
    
                # 影片导演、主演、年份、国家、类型
                bd = re.findall(findBd, item)[0]
                bd = re.sub('<br(\s+)?/>(\s+)?', " ", bd)
                bd = re.sub('/', " ", bd)
                data.append(bd.strip())  # bd.strip()去空格
                print("bd:" + bd)
                # 使用一个影片测试的时候,可以放开break
                # break
    
                # 将html解析后的信息加入到datalist中
                datalist.append(data)
        return datalist
    
    
    # 3.保存数据
    def saveData(savepath):
        print("todo---save")
    
    
    # 其他单独方法
    
    # 得到一个指定url内容的方法
    def askURL(url):
        html = ""
        # 模拟浏览器请求头信息
        head = {
            # 用户代理,告诉服务器我们是什么类型的机器/浏览器,本质是告诉服务器我们能接收什么水平的文件
            # 从浏览器F12里复制时请尽量让该信息在一行里显示再赋值,不然复制过来也是多行而且数据中间有很多空格,有可能出问题
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3870.400 QQBrowser/10.8.4405.400"
        }
        # 模拟的总请求信息
        request = urllib.request.Request(url, headers=head)
        try:
            response = urllib.request.urlopen(request)
            html = response.read().decode("utf-8")
            # 可以输出测试
            # print(html)
    
        except urllib.error.URLError as e:
            # 如果e有code,打印code
            if hasattr(e, "code"):
                print(e.code)
            # 如果e有reason,打印reason
            if hasattr(e, "reason"):
                print(e.reason)
        return html
    
    
    if __name__ == '__main__':
        main()
    
    

    打断点可以看到查到了250条记录并存到了datalist里:
    在这里插入图片描述

    3.4保存数据

    3.4.1保存到excel中

    在这里插入图片描述
    小试一下:
    testXwlt.py:

    # -*- coding = utf-8 -*-
    # @Time : 2021/7/21 17:15
    # @Author : coderhao
    # @File : testXwlt.py
    # @Software : PyCharm
    
    import xlwt
    
    # 创建workbook对象,最后会对应成一个.xls
    workbook = xlwt.Workbook(encoding="utf-8")
    # 创建worksheet对象,最后会对应成xls里面的一个sheet
    worksheet = workbook.add_sheet("sheet1")
    # 写入数据,在坐标(0,0)上写入hello
    worksheet.write(0, 0, "hello")
    # 持久化xls
    workbook.save("student.xls")
    

    在这里插入图片描述
    在这里插入图片描述
    小例子,99乘法表:
    99chengfabiao.py:

    #-*- coding = utf-8 -*-
    #@Time : 2021/7/21 19:23
    #@Author : coderhao
    #@File : 99chengfabiao.py
    #@Software : PyCharm
    
    import xlwt
    
    # 案例:在xls里保存99乘法表
    def sav99():
        # 创建workbook对象,最后会对应成一个.xls
        workbook = xlwt.Workbook(encoding="utf-8")
        # 创建worksheet对象,最后会对应成xls里面的一个sheet
        worksheet = workbook.add_sheet("sheet1")
        # i:1--9
        for i in range(1, 10):
            # j:1--i
            for j in range(1, i + 1):
                result = "%d*%d=%d" % (i, j, i * j)
                # print(result)
                worksheet.write(i - 1, j - 1, result)
    
        workbook.save("99乘法表.xls")
    
    
    if __name__ == '__main__':
        sav99()
    

    99乘法表.xls:
    在这里插入图片描述

    3.4.2完善pachong.py-数据持久化到xls中

    # -*- coding = utf-8 -*-
    # @Time : 2021/7/19 17:18
    # @Author : coderhao
    # @File : pachong.py
    # @Software : PyCharm
    
    # 网页解析,获取数据
    from bs4 import BeautifulSoup
    # 正则表达式,文字匹配
    import re
    # 制定url,获取网页数据
    import urllib.request, urllib.error
    # 进行excel操作
    import xlwt
    # 进行sqlite数据库操作
    import sqlite3
    
    
    def main():
        # 访问url
        baseurl = "https://movie.douban.com/top250?start="
        # 保存路径
        savepath = "doubanTop250.xls"
        # 1.爬取网页
        datalist = getData(baseurl)
        # 3.保存数据
        saveData(savepath, datalist)
    
    
    # 全局变量
    # re.compile()创建正则规则
    '''
    对照规则:
    <div class="item">
    <div class="pic">
    <em class="">1</em>
    <a href="https://movie.douban.com/subject/1292052/">
    <img alt="肖申克的救赎" class="" src="https://img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg" width="100"/>
    </a>
    </div>
    <div class="info">
    <div class="hd">
    <a class="" href="https://movie.douban.com/subject/1292052/">
    <span class="title">肖申克的救赎</span>
    <span class="title"> / The Shawshank Redemption</span>
    <span class="other"> / 月黑高飞(港)  /  刺激1995(台)</span>
    </a>
    <span class="playable">[可播放]</span>
    </div>
    <div class="bd">
    <p class="">
                                导演: 弗兰克·德拉邦特 Frank Darabont   主演: 蒂姆·罗宾斯 Tim Robbins /...<br/>
                                1994 / 美国 / 犯罪 剧情
                            </p>
    <div class="star">
    <span class="rating5-t"></span>
    <span class="rating_num" property="v:average">9.7</span>
    <span content="10.0" property="v:best"></span>
    <span>2399691人评价</span>
    </div>
    <p class="quote">
    <span class="inq">希望让人自由。</span>
    </p>
    </div>
    </div>
    </div>
    '''
    findlink = re.compile(r'a href="(.*?)">')
    # re.S忽略换行符
    # findImgSrc=re.compile(r'<img.*src="(.*?)" width="100"/>',re.S)
    findImgSrc = re.compile(r'<img alt=".*" class="" src="(.*?)" width="100"/>', re.S)
    findTitle = re.compile(r'<span class="title">(.*?)</span>')
    findRating = re.compile(r'<span class="rating_num" property="v:average">(.*?)</span>')
    findJudge = re.compile(r'<span>(\d*?)人评价</span>')
    findInq = re.compile(r'<span class="inq">(.*?)</span>')
    findBd = re.compile(r'<p class="">(.*?)</p>', re.S)
    
    
    # 1.爬取网页
    def getData(baseurl):
        print("start:getData()")
        datalist = []
        # 通过循环得到所有的url
        # range函数左闭右开
        for i in range(0, 10):
            url = baseurl + str(i * 25)
            html = askURL(url)
            # 2.解析数据
            # 第一步网页爬取是个循环过程,所以,解析过程也是跟在爬到的每个网页后面的,更恰当地说这一步应该是在第一步内部
            # 解析器选择,并解析
            soup = BeautifulSoup(html, "html.parser")
            # 遍历符合要求的字符串,形成列表。需要的是<div class="info">的内部内容
    
            for item in soup.find_all("div", class_="item"):
                # item存的一个电影的信息
                # print(item)
                # 用来保存一部电影的所有信息
                data = []
                item = str(item)
    
                # 影片详情链接
                link = re.findall(findlink, item)[0]
                # print("link:" + link)
                data.append(link)
    
                # 影片图片url
                imgSrc = re.findall(findImgSrc, item)[0]
                # print("imgSrc:" + imgSrc)
                data.append(imgSrc)
    
                # 影片题目
                title = re.findall(findTitle, item)
                if (len(title) == 2):
                    # 中文名
                    ctitle = title[0]
                    # 外文名
                    otitle = title[1].replace("/", "")  # 去掉/
                    data.append(ctitle)
                    data.append(otitle)
                else:
                    data.append(title[0])
                    data.append(' ')  # 留空
                # print("ctitle:" + ctitle + "otitle:" + otitle)
    
                # 影片评分
                rating = re.findall(findRating, item)[0]
                # print("rating:" + rating)
                data.append(rating)
    
                # 评分人数
                judge = re.findall(findJudge, item)[0]
                # print("judge:" + judge)
                data.append(judge)
    
                # 影片简述
                inq = re.findall(findInq, item)
                if (len(inq) != 0):
                    inq = inq[0].replace("。", "")
                    data.append(inq)
                else:
                    data.append(" ")
                    inq = " "
                # print("inq:" + inq)
    
                # 影片导演、主演、年份、国家、类型
                bd = re.findall(findBd, item)[0]
                bd = re.sub('<br(\s+)?/>(\s+)?', " ", bd)
                bd = re.sub('/', " ", bd)
                data.append(bd.strip())  # bd.strip()去空格
                # print("bd:" + bd)
                # 使用一个影片测试的时候,可以放开break
                # break
    
                # 将html解析后的信息加入到datalist中
                datalist.append(data)
        print("finished:getData()")
        return datalist
    
    
    # 3.保存数据
    def saveData(savepath, datalist):
        print("start:saveData()")
        # 创建workbook对象,最后会对应成一个.xls。style_compression=0:样式压缩
        workbook = xlwt.Workbook(encoding="utf-8", style_compression=0)
        # 创建worksheet对象,最后会对应成xls里面的一个sheet。cell_overwrite_ok=True:覆盖单元格
        worksheet = workbook.add_sheet("豆瓣电影top250", cell_overwrite_ok=True)
        col = ("电影详情链接", "电影图片链接", "电影题目(中)", "电影题目(外/繁)", "电影评分", "评分人数", "电影简评", "相关信息")
        # 填充列名
        for i in range(0, len(col)):
            worksheet.write(0, i, col[i])
        for i in range(0, len(datalist)):
            data=datalist[i]
            for j in range(0,len(data)):
                worksheet.write(i+1, j, data[j])
            print("写入了第%d部电影信息" % (i + 1))
        workbook.save(savepath)
        print("finished:saveData()")
    
    
    # 其他单独方法
    
    # 得到一个指定url内容的方法
    def askURL(url):
        html = ""
        # 模拟浏览器请求头信息
        head = {
            # 用户代理,告诉服务器我们是什么类型的机器/浏览器,本质是告诉服务器我们能接收什么水平的文件
            # 从浏览器F12里复制时请尽量让该信息在一行里显示再赋值,不然复制过来也是多行而且数据中间有很多空格,有可能出问题
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3870.400 QQBrowser/10.8.4405.400"
        }
        # 模拟的总请求信息
        request = urllib.request.Request(url, headers=head)
        try:
            response = urllib.request.urlopen(request)
            html = response.read().decode("utf-8")
            # 可以输出测试
            # print(html)
    
        except urllib.error.URLError as e:
            # 如果e有code,打印code
            if hasattr(e, "code"):
                print(e.code)
            # 如果e有reason,打印reason
            if hasattr(e, "reason"):
                print(e.reason)
        return html
    
    
    if __name__ == '__main__':
        main()
        print("爬取完毕!")
    
    
    

    在这里插入图片描述
    打开xls文件可以看到相关信息已全部录入:
    在这里插入图片描述

    3.4.3完善pachong.py-数据持久化到数据库中

    首先安装sqlalchemy,作用和java中的mybatis差不多

    pip3 install sqlalchemy
    pip3 install pymysql
    

    可选:或者像原来一样从setting里安装也行:
    在这里插入图片描述
    pachong.py:

    # -*- coding = utf-8 -*-
    # @Time : 2021/7/19 17:18
    # @Author : coderhao
    # @File : pachong.py
    # @Software : PyCharm
    
    # 网页解析,获取数据
    from bs4 import BeautifulSoup
    # 正则表达式,文字匹配
    import re
    # 制定url,获取网页数据
    import urllib.request, urllib.error
    # 进行excel操作
    import xlwt
    # 进行sqlite数据库操作
    import sqlite3
    
    
    def main():
        # 访问url
        baseurl = "https://movie.douban.com/top250?start="
        # 保存路径
        savepath = "doubanTop250.xls"
        # 1.爬取网页
        datalist = getData(baseurl)
        # 3.保存数据(excel/mysql二选一)
        # 3.1使用excel保存数据
        # saveData1(savepath, datalist)
        # 3.2使用mysql保存数据
        saveData2(datalist)
    
    # 全局变量
    # re.compile()创建正则规则
    '''
    对照规则:
    <div class="item">
    <div class="pic">
    <em class="">1</em>
    <a href="https://movie.douban.com/subject/1292052/">
    <img alt="肖申克的救赎" class="" src="https://img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg" width="100"/>
    </a>
    </div>
    <div class="info">
    <div class="hd">
    <a class="" href="https://movie.douban.com/subject/1292052/">
    <span class="title">肖申克的救赎</span>
    <span class="title"> / The Shawshank Redemption</span>
    <span class="other"> / 月黑高飞(港)  /  刺激1995(台)</span>
    </a>
    <span class="playable">[可播放]</span>
    </div>
    <div class="bd">
    <p class="">
                                导演: 弗兰克·德拉邦特 Frank Darabont   主演: 蒂姆·罗宾斯 Tim Robbins /...<br/>
                                1994 / 美国 / 犯罪 剧情
                            </p>
    <div class="star">
    <span class="rating5-t"></span>
    <span class="rating_num" property="v:average">9.7</span>
    <span content="10.0" property="v:best"></span>
    <span>2399691人评价</span>
    </div>
    <p class="quote">
    <span class="inq">希望让人自由。</span>
    </p>
    </div>
    </div>
    </div>
    '''
    findlink = re.compile(r'a href="(.*?)">')
    # re.S忽略换行符
    # findImgSrc=re.compile(r'<img.*src="(.*?)" width="100"/>',re.S)
    findImgSrc = re.compile(r'<img alt=".*" class="" src="(.*?)" width="100"/>', re.S)
    findTitle = re.compile(r'<span class="title">(.*?)</span>')
    findRating = re.compile(r'<span class="rating_num" property="v:average">(.*?)</span>')
    findJudge = re.compile(r'<span>(\d*?)人评价</span>')
    findInq = re.compile(r'<span class="inq">(.*?)</span>')
    findBd = re.compile(r'<p class="">(.*?)</p>', re.S)
    
    
    # 1.爬取网页
    def getData(baseurl):
        print("start:getData()")
        datalist = []
        # 通过循环得到所有的url
        # range函数左闭右开
        for i in range(0, 10):
            url = baseurl + str(i * 25)
            html = askURL(url)
            # 2.解析数据
            # 第一步网页爬取是个循环过程,所以,解析过程也是跟在爬到的每个网页后面的,更恰当地说这一步应该是在第一步内部
            # 解析器选择,并解析
            soup = BeautifulSoup(html, "html.parser")
            # 遍历符合要求的字符串,形成列表。需要的是<div class="info">的内部内容
    
            for item in soup.find_all("div", class_="item"):
                # item存的一个电影的信息
                # print(item)
                # 用来保存一部电影的所有信息
                data = []
                item = str(item)
    
                # 影片详情链接
                link = re.findall(findlink, item)[0]
                # print("link:" + link)
                data.append(link)
    
                # 影片图片url
                imgSrc = re.findall(findImgSrc, item)[0]
                # print("imgSrc:" + imgSrc)
                data.append(imgSrc)
    
                # 影片题目
                title = re.findall(findTitle, item)
                if (len(title) == 2):
                    # 中文名
                    ctitle = title[0]
                    # 外文名
                    otitle = title[1].replace("/", "")  # 去掉/
                    data.append(ctitle)
                    data.append(otitle)
                else:
                    data.append(title[0])
                    data.append(' ')  # 留空
                # print("ctitle:" + ctitle + "otitle:" + otitle)
    
                # 影片评分
                rating = re.findall(findRating, item)[0]
                # print("rating:" + rating)
                data.append(rating)
    
                # 评分人数
                judge = re.findall(findJudge, item)[0]
                # print("judge:" + judge)
                data.append(judge)
    
                # 影片简述
                inq = re.findall(findInq, item)
                if (len(inq) != 0):
                    inq = inq[0].replace("。", "")
                    data.append(inq)
                else:
                    data.append(" ")
                    inq = " "
                # print("inq:" + inq)
    
                # 影片导演、主演、年份、国家、类型
                bd = re.findall(findBd, item)[0]
                bd = re.sub('<br(\s+)?/>(\s+)?', " ", bd)
                bd = re.sub('/', " ", bd)
                data.append(bd.strip())  # bd.strip()去空格
                # print("bd:" + bd)
                # 使用一个影片测试的时候,可以放开break
                # break
    
                # 将html解析后的信息加入到datalist中
                datalist.append(data)
        print("finished:getData()")
        return datalist
    
    # 3.保存数据
    # 3.1保存到excel中
    def saveData1(savepath, datalist):
        print("start:saveData()")
        # 创建workbook对象,最后会对应成一个.xls。style_compression=0:样式压缩
        workbook = xlwt.Workbook(encoding="utf-8", style_compression=0)
        # 创建worksheet对象,最后会对应成xls里面的一个sheet。cell_overwrite_ok=True:覆盖单元格
        worksheet = workbook.add_sheet("豆瓣电影top250", cell_overwrite_ok=True)
        col = ("电影详情链接", "电影图片链接", "电影题目(中)", "电影题目(外/繁)", "电影评分", "评分人数", "电影简评", "相关信息")
        # 填充列名
        for i in range(0, len(col)):
            worksheet.write(0, i, col[i])
        for i in range(0, len(datalist)):
            data=datalist[i]
            for j in range(0,len(data)):
                worksheet.write(i+1, j, data[j])
            print("写入了第%d部电影信息" % (i + 1))
        workbook.save(savepath)
        print("finished:saveData()")
    # 3.2保存到mysql中
    '''
    sql建表语句:
    CREATE TABLE `douban_top250` (
      `id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
      `link` varchar(100) DEFAULT NULL COMMENT '影片详情链接',
      `imgSrc` varchar(100) DEFAULT NULL COMMENT '影片图片url',
      `ctitle` varchar(100) DEFAULT NULL COMMENT '影片题目(中)',
      `otitle` varchar(100) DEFAULT NULL COMMENT '影片题目(外/繁)',
      `rating` varchar(100) DEFAULT NULL COMMENT '影片评分',
      `judge` bigint DEFAULT NULL COMMENT '评分人数',
      `inq` varchar(100) DEFAULT NULL COMMENT '影片简述',
      `bd` varchar(200) DEFAULT NULL COMMENT '影片导演、主演、年份、国家、类型',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
    '''
    # 将保存到excel中的方法设为saveData1,保存到mysql中的方法设为saveData2
    def saveData2(datalist):
        from sqlalchemy.ext.declarative import declarative_base
        from sqlalchemy import create_engine, Column, Integer, String
        from sqlalchemy.orm import sessionmaker
    
        HOST = 'localhost'
        PORT = 3306
        USERNAME = 'root'
        PASSWORD = 'password'
        DB = 'security_enterprise'  #数据库名
    
        # dialect + driver://username:passwor@host:port/database
        # +'?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true'
        DB_URI = f'mysql+pymysql://{USERNAME}:{PASSWORD}@{HOST}:{PORT}/{DB}'
    
        # 创建基类
        BASE = declarative_base()
    
        # 定义Movie对象
        # 定义ORM映射对象时,要与建表语句保持一致
        class Movie(BASE):
            # 表的名字:douban_top250
            __tablename__ = 'douban_top250'
            # id
            id = Column(Integer, primary_key=True, autoincrement=True)
            # 学号
            link = Column(String(100))
            # imgSrc
            imgSrc = Column(String(100))
            # ctitle
            ctitle = Column(String(100))
            # otitle
            otitle = Column(String(100))
            # rating
            rating = Column(String(100))
            # judge
            judge = Column(Integer)
            # inq
            inq = Column(String(100))
            # bd
            bd = Column(String(200))
            # 创建表的参数
            __table_args__ = {
                "mysql_charset": "utf8"
            }
    
        try:
            # 连接MySQL数据库
            MySQLEngine = create_engine(DB_URI)
            # 创建MySQL类型
            MySQLSession = sessionmaker(bind=MySQLEngine)
            # 创建session对象
            session = MySQLSession()
    
            # 使用ORM插入数据
            for i in range(0,len(datalist)):
                data=datalist[i]
                # 创建movie对象
                movie=Movie(link=data[0],imgSrc=data[1],ctitle=data[2],otitle=data[3],rating=data[4],judge=data[5],inq=data[6],bd=data[7])
                # 将创建的对象添加进session中
                session.add(movie)
    
    
            # 使用原生SQL插入数据
            # session.execute(
            #     "INSERT INTO STUDENT VALUES('2016081115','吴芳'),('2016081116','胡月')")
            
            # 提交到数据库
            # 如果提交失败,会自动回滚
            session.commit()
            # 关闭session
            session.close()
            print('插入MySQL数据库成功')
        except Exception as e:
            print("插入MySQL数据库失败", e)
    
    
    
    # 其他单独方法
    
    # 得到一个指定url内容的方法
    def askURL(url):
        html = ""
        # 模拟浏览器请求头信息
        head = {
            # 用户代理,告诉服务器我们是什么类型的机器/浏览器,本质是告诉服务器我们能接收什么水平的文件
            # 从浏览器F12里复制时请尽量让该信息在一行里显示再赋值,不然复制过来也是多行而且数据中间有很多空格,有可能出问题
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3870.400 QQBrowser/10.8.4405.400"
        }
        # 模拟的总请求信息
        request = urllib.request.Request(url, headers=head)
        try:
            response = urllib.request.urlopen(request)
            html = response.read().decode("utf-8")
            # 可以输出测试
            # print(html)
    
        except urllib.error.URLError as e:
            # 如果e有code,打印code
            if hasattr(e, "code"):
                print(e.code)
            # 如果e有reason,打印reason
            if hasattr(e, "reason"):
                print(e.reason)
        return html
    
    
    if __name__ == '__main__':
        main()
        print("爬取完毕!")
    

    在数据库中可以看到已经存入:
    在这里插入图片描述

    展开全文
    anotherQu 2021-07-19 16:06:24
  • 一 基本知识1 数据类型类似于c/c++对于long类型常量书写时,要在数字后面加上L或者l。0L对于float类型常量书写时,要在小数点后面加上F或者f。0.0F对于double类型常量书写时,要在小数点后面加上D或者d。...

    一  基本知识

    1 数据类型

    类似于c/c++

    51899785_1.jpg

    对于long类型常量书写时,要在数字后面加上L或者l。0L    对于float类型常量书写时,要在小数点后面加上F或者f。0.0F    对于double类型常量书写时,要在小数点后面加上D或者d。 0.0D

    数据类型之间的转换Java中也有隐式转换(Java则叫做自动转换)和显式转换(Java则叫做强制转换)。自动转换由编译器实现,强制转换则由用户编程实现,再由编译器执行。自动转换的规则:低级数据类型 ==》 高级数据类型;所占字节数低的数据类型 ==》 所占字节数高的数据类型例如:byte short int long(整数类型) ==》 float double(浮点数类型)      byte short(8字节和16字节) ==》int(32字节)      byte short int(8字节,16字节和32字节) ==》 long(64字节)      float(32字节) ==》 double(64字节)      char(16字节) ==》 int(32字节)注:整数类型中的long,虽然占64个字节,但是却能自动转换成float类型(32字节)。因此,我认为,在自动转换的过程中,先考虑数据类型的等级高低,再考虑数据类型的所占字节数。再注:从简单数据类型图中不难看出,各数据类型的长度均为固定值,这使得Java能够在不同的平台上运行相同的Java程序时不用修改代码,提高了程序的可移植特性。

    2  头文件

    (1)类似于c++的命名空间或者是头文件

    在JAVA中叫做包(package)。Java的核心包中,我们常用的有这样5种:(1)java.lang , 封装了所有编写java程序所需要的基本类,包括Object、Class、System等。其中,Object类是所有类的根类,任何类都是继承该类而建立的;Class类是由编译器动态生成对象的一个伴随每一个类的特殊类;System类是一个final类,主要提供标准I/O和对系统环境信息的访问等,这个类不能被实例化。(2)java.awt , 窗口工具包,提供操作图形用户界面的基本功能。(3)java.applet , 封装Applet类的包,提供Applet执行时需要的类。(4)java.io , 封装I/O操作的包。(5)java.util , 提供使用程序类以及集合类等常用的工具类。

    3 程序结构

    首先,是package语句,用来指定源文件所在的包。

    然后,是public classDefinitiom,也就是公共类,用来指定源文件的类名,这个类名要与源文件名相同,可有0个或1个。

    再然后,是classDefinition,也就是一般类,可以有若干个,也可以没有。注:一个java源文件中,最多只能有一个public类,且必须与文件名相同。我们的第一个程序:

    import java.lang.*;import java.io.*;class matrix  //一般类 {         void luoyang1()   {   } }public class Matrixkey //public类,类名要与文件名相同{          public static void main(String args[])     {        System.out.println("很高兴认识你,我是Matrixkey");      }}

    4Java的解释执行

    在系统运行Java程序时,Java编译器将Java程序(*.java文件)转化为字节码(*.class文件),在运行时,解释器将编译得到的字节码进行解释执行。Java语言一个源程序可以含有多个类(public类最多一个),每个类编译都生成一个字节码文件。也就是说,有几个类,就有几个字节码文件。这就是,我们在执行一个Java程序时要先用javac *.java将Java程序转化为字节码的原因。注:Java区分大小写,因此上面的程序中,public类的类名:Matrixke,那么这个java程序的文件名必须为:Matrixkey.java

    5 输入输出

    输出使用println方法。println方法的使用方法如下:System.out.println(x);

    System是java.lang.*包中的类,out是System类的一静态属性,而println()是out属性的一个静态方法。该方法用于打印后再换行,可以打印基本类型的数据以及字符串等,'+' 在字符串中代表将字符串相互连接。int x = 4772;        /* 输出一个字符m */        System.out.println(m);         * 输出一个数字4772 */        System.out.println("变量x等于"+x); //或者直接System.out.println(x);     /* 输出一个字符串matrixkey */        System.out.println("matrixkey");        /* 输出汉字落阳*/System.out.println("落阳");

    println方法打印后自动换行,因此,下面2条代码输出结果是一致的int x = 100;System.out.println(x);System.out.print(x + "\n");

    注意:"+"号用来连接字符串是有点麻烦的! 例如:System.out.println(1+2+"3"); Sysrem.out.println("1"+2+3); '+'号优先级别,从左到右 所以打印结果是这样的:33(先做1+2 变成字符串"3" 连接后面的"3",所以打印33) 123(先把"1"和2连接成为"12",在连接3就变成"123")

    6 运算符和流程控制

    C/C++类似,注意switch不能做实数的判断

    二 类

    1 概念

    类作为JAVA程序的基本要素,由成员变量(即属性)和成员方法组成,必须先定义在使用。类声明格式:[修饰符] class 类名 [extends 父类名] [implements 类实现的接口列表](1)修饰符用于确定类的访问控制权限(public和friendly)以及类型(abstract和final)(2)类名是合法的标识符,并且首字母大写(3)保留字extends指明声明的类所继承的父类(4)[ ]里的内容可选/* JAVA中类的声明和继承*/public class Matrixkey{成员变量 成员方法} class Matrix extends Matrixkey

    /* C#中类的声明和继承*/public class Matrixkey{成员变量 成员方法} class Matrixk : Matrixkey

    类体格式:class 类名 {成员变量 成员方法}其中成员变量定义的格式为: 成员方法定义的格式为: ( [ ] )(1)成员变量和成员方法可以通过public private protected等修饰符控制访问权限(2)java中,方式是通过值传递参数,而不是通过地址,因此方法不可以改变参数的值例:public class Matrixkey  //类声明 { public int a;    public double b;        //成员变量的声明        static void Min(double c)  //成员方法的声明  }

    类成员的修饰符有两种访问限定符:public  可以被外部类访问                        protected  可以被同一个包中的类以及该类的子类访问                        private  只能在该类内部被访问default  可以被同一个包中的类访问非访问限定符:静态修饰符 static                            最终修饰符  final       抽象修饰符 abstract  syncronized

    2 类的继承在java语言中,类继承是通过extends保留字实现的,格式为:

    class Subclass extends Superclass {...}

    (1) 用extends指明新定义的子类(Subclass)的父类(Superclass),就在两个类之间建立了继承的关系(2)子类可以从父类继承所有非private的属性和方法作为自己的成员(3)若子类成员变量的名字 和 父类成员变量的名字 相同,则子类成员隐藏父类成员(4)若子类成员方法 与 父类成员方法的名字,返回值类型,参数表都相同,则子类方式是父类方法的重写(5)方法重写时注意:子类方法的访问权限要高于父类

    子类方法的访问权限比父类方法的访问权限要高,一般用Super关键字来访问父类的方法和变量,但是父类的对象不能直接访问子类的方法和变量

    3  数组定义一维数组的格式: [ ]; 或者 [ ] ;因此,int A [ ]; int [ ] A ; 两者是相同的(1)可以是简单或者复杂数据类型(2)进行数组定义时,不分配内存,因此不要求给出其元素的个数(3)数组分配内存通过new操作符或静态初始化实现创建一维数组的格式: = new [ ];A = new int [3];定义的同时创建: [ ] 数组名 = new [ ];int [ ] A = new int [3];初始化数组:对已定义的数组元素赋值,有动态和静态两种方式(1)当初始化元素数目较少,采用静态初始化int A[ ];A[0] = 1; A[1] = 2;A[2] = 3;(2)对简单类型,定义数组的同时,用new操作符进行初始化int [ ] A = new int [3]{1,2,3};(3)当初始化元素数目较多,可以利用循环语句对数组元素动态初始化

    多维数组定义的格式: [ ] [ ];  或者 [ ] [ ] ;初始化:在定义的同时对数组元素进行赋值(静态)可以按顺序直接对每一维分配内存或从最高维开始对每一维分配内存(动态)数组操作(1)方法arraycopy()用来进行数组的拷贝(2)ArrayList类用来动态调整数组的大小

    4 字符串的表示(1)用String类表示字符串,String类的对象表示的是固定长度的字符串(2)用StringBuffer类表示字符串,StringBuffer类的每个对象都是长度可变的字符串字符串的操作(1)对String的修改String类提供了concat() replace() substring()方法分别实现字符串的连接,替换,取子串的操作;“+”运算符也可以用来连接字符串。(2)对StringBuffer的修改StringBuffer类表示的是可变长度的字符串,使用它,就可以方便地在字符串中插入或在字符串尾追加字符。相应的方法是:insert(),setCharAt(),append()。(3)判断两个字符串是否相等,使用equals()方法

    三  异常处理

    参考类似c/c++。

    对于try和catch子句的排列方式,下列哪个是正确的?A。 子类异常在前,父类异常在后B。 父类异常在前,子类异常在后C。 只能有子类异常D。 父类异常和子类异常不能同时出现在同一个try程序段内解析:在java语言中,在捕获父类异常时对其子类异常也捕获了,根据try与catch的匹配原则,尽量使用一个父类去捕获其所有子类的异常,而父类和子类异常是可以同时出现的。答案:A

    展开全文
    weixin_39610785 2021-03-10 07:14:10
  • weixin_34977617 2021-01-14 10:27:58
  • weixin_45434902 2021-09-22 09:11:03
  • xza13155 2021-03-09 15:52:09
  • weixin_45434902 2021-10-02 12:17:55
  • weixin_31635881 2021-03-05 18:49:25
  • m0_46639258 2021-05-23 23:16:52
  • aiqq136 2021-01-30 19:37:38
  • 3星
    8KB lcp1505371914 2011-10-22 09:43:56
  • weixin_33390899 2021-06-09 08:36:07
  • weixin_49047177 2021-12-11 16:56:33
  • weixin_29007809 2021-05-26 04:03:33
  • weixin_36346970 2021-03-04 08:23:01
  • LingLing1301 2021-10-30 16:18:51
  • weixin_45955767 2021-11-22 01:31:54
  • weixin_39805851 2020-12-24 07:04:54
  • qq_45750937 2021-12-06 01:21:59
  • m0_51457210 2021-07-18 19:45:10
  • qq_38351824 2019-10-05 22:01:40
  • rizero 2021-01-13 20:23:38
  • qq_41061477 2021-03-15 22:56:17
  • weixin_28829903 2021-02-05 14:12:30
  • shirlleyHan 2021-01-15 19:24:41
  • weixin_48746231 2021-03-05 15:47:17

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 37,653
精华内容 15,061
关键字:

速成

友情链接: menu-demo.zip