Java 黑马最新29期基础班 第二天导师讲义,很适合初学者

今日内容

  • 运算符
    * 算数运算符
    * 自增自减运算符
    * 赋值运算符
    * 逻辑运算符
    * 比较运算符
    * 三元运算符
  • 数据输入(键盘录入)
    * 实现人机交互, 使程序运算的数据变得更加灵活
  • 流程控制语句(重点★★★★★)

1. 算术运算符

  • 运算符
    * 对常量和变量进行操作的符号
    *
    * System.out.println(10 + 20); // 2个常量进行加法运算!
    * int a = 1;
    * int b = 2;
    * System.out.println(a + b);
  • 表达式
    * 用运算符把常量或者变量连接起来符号,java语法的式子就可以称为表达式。
    1. 运算符的分类?
    1. 算数运算符有哪些?
总结:
	1.
		算术运算、赋值运算、自增自减运算、关系运算符、逻辑运算符、三元运算符
	2. 
        + 加法运算
        — 减法运算
        * 乘法运算
        / 除法运算(获得的是商)
        % 除法运算(获得的是余数) ★★★★★					
  • 算术运算符取余和除法的区别
    * / 得到的是商
    * % 得到的余数
问题:
	12345 / 100 等于多少?	123

	12345 % 100 等于多少?	45
	
	12345 / 100 % 100 等于多少?	 123%100 = 23
  • 注意:
    整数相除结果只能是整数, 如果想计算出小数, 必须要有浮点类型数据参数运算
public class Demo01{
	public static void main(String[] args){
		double num = 12.5;
		int a = 3;
		System.out.println(num+a); // 15.5
		System.out.println(num-a); // 9.5
		System.out.println(num*a); // 37.5
		System.out.println(num/a); // 4.166666666666667
		System.out.println(num%a); // 0.5	
	}
}

2. 字符的+操作【一般用于面试】

  • 思考: System.out.println(‘a’ + 1); // 输出结果? // 98

字符参与运算的时候,会将字符转成对应码表(万国码)的数值

  • 注意: 当char类型在跟整数类型的数据进行运算的时候, 实际上是?
它会将char类型的数据根据底层的码表进行转换成对应的数值(int类型),然后参与运算!
本质:它在进行一个数据类型提升!char---->>>int
  • 重点关注:
1. char类型在和整数类型运算的时候, 会查找底层的ASCII数值(万国码), 然后再运算
2. 小的数据类型在和大的数据类型相加的时候, 会先将小的数据类型提升为大的之后, 再进行运算.
  • 结论:
    不同的基本数据类型参与运算时,整个算术表达式的类型会自动进行提升,提升为参与运算的最高等级。
  double d = 'a'+3.14;  // 首先将字符a提升为int类型,与double类型的数据进行加法运算,会将字符a对应的int类型的数值97转成double类型的97.0,最后与double类型的3.14进行运算!
提升规则:
	单独记忆 : byte类型,short类型和char类型将被提升到int类型

	整个表达式的类型自动提升到表达式中最高等级操作数相同的类型
	等级顺序:byte,short,char , int , long , float , double  

3. 字符串的+操作【一般用于开发】

  • 字符串在与[任意数据类型]用+号串联的时候都会 ?
进行字符串拼接!(不是进行运算的!),如果有多个+出现,它会从左到右依次执行!
  • 结论: 有了字符串的+操作,以后我们打印的效果会更加友好!
public class Demo03{
	public static void main(String[] args){
		int a = 1;
		int b = 3;
		System.out.println("2个变量的和是:"+(a+b));  // 2个变量的和是:4
        System.out.println("2个变量的和是:"+a+b);  // 2个变量的和是:13
	}
}
  • 5分钟时间练习
定义两个变量:
	int a = 3;
	int b = 4;
	请输出字符串格式的:3 + 4 = 7

public class Demo04{
	public static void main(String[] args){
		int a = 5;
		int b = 7;
		//System.out.println("3 + 4 = "+(a+b));  // 3 + 4 = 7  
		// 将常量3删除,写2个 "",然后在这个""里面写2个+  【“+变量名称+”】
  		System.out.println(""+a+" + "+b+" = "+(a+b));  // 5 + 7 = 12
  		System.out.println("请输出字符串格式的:"+a+"+"+b+" ="+(a+b)); // 请输出字符串格式的:5+7 =12
	}
}			
  • +号总结
1.运算:
	int sum = 3+4;
2.表示正数:
	System.out.println(+10);
3.进行字符操作:
	首先会将字符提升了int类型的数字(字符在码表中对应的数值),然后参与运算!
		单独:  byte short char ======>>> 直接提升为int 
			(1个byte和1个short相加的结果是 int【先分别将byte和short提升为int,最终是2个int相加】 )
		与其它的(long float double)一起运算,最终得到的是大范围的!
4.字符串拼接:
	字符串与任意类型进行+操作,都是在进行拼接!!!!!
	多个+,默认是从左到右执行!

4. 赋值运算符

  • 赋值运算符有哪些? 具体能完成什么操作?
总结:
	基本的赋值运算符:
    	=	将=号右侧的数值赋值给左侧的变量!  int num = 20;
	扩展的赋值运算符:
		+=	将+=左侧变量的值与右侧的数值进行加法运算,得到结果赋值给左侧的变量  num+=30; // num = 50
		-=	将-=左侧变量的值与右侧的数值进行减法运算,得到结果赋值给左侧的变量  num-=20; // num = 30
		*=	将*=左侧变量的值与右侧的数值进行乘法运算,得到结果赋值给左侧的变量  num*=30; // num = 900
		/=	将/=左侧变量的值与右侧的数值进行除法运算,得到商赋值给左侧的变量    num/=20; // num = 45
		%=	将%=左侧变量的值与右侧的数值进行除法运算,得到余数赋值给左侧的变量  num%=6;  // num = 3 
	
		num+=30  等价于 num = num+30
		……
		……	

​ 问题★★★★★:【笔试题】
​ 下面的程序是否有问题,如果有问题,请指出并说明理由(必须掌握!!!)

	short s = 1;    
	s = s+1;			//  s先会提示为int,2个int相加得到int,赋值给short,报错!

	short s=1;    
	s = (short)(s+1);	// s是short类型, 在跟常量1做运算的时候, 会先提升为int再做运算
						// 两个int相加的结果还是int, 将int赋值给一个short变量, 需要加入强制转换符.
					
	System.out.println(s);		
	
	short s=1;
    s += 1;			

	short s=1;
	s += 1;		// s = (short)(s + 1);
				// += 符号, 底层自动帮我们做了强制转换
	System.out.println(s);	
	
结论:以后出现  num = num+100 ====>>>num+=100;	

5. 自增自减运算符

  • ++ – 运算符的基本应用是?
  • 单独使用有什么效果?
  • 参与运算使用有什么效果?
总结:
	1. 就是在原始值的基础上 +1(++操作)或者-1(--操作)
	2.【单独使用,开发居多!】
		自增: ++ 
			前置++	++i
			后置++	i++   
		自减:--
			前置--	--i
			后置--	i--
		单独使用:不论是前置(++或者--)还是后置,没有什么区别,都是在原始值的基础上+1或者-1
	3.【参与运算,面试经常出现】
    	前置++	++i		int j = ++i;	先让i的值+1,然后将+1后的结果赋值给j
		后置++	i++		int j = i++;	先将i的值赋值给j,然后i自己+1
		前置--	--i		int j = --i;	先让i的值-1,然后将-1后的结果赋值给j
		后置--	i--		int j = i--;	先将i的值赋值给j,然后i自己-1
注意事项(★★★★★): ++, --运算符只能操作变量, 不能操作常量.
	++4 5--  // 错误的!
  • 看程序写结果
看程序写结果
	int x = 10;
	int y = x++;	// 	x=11 y=10		
	int z = ++x;	//  x=12 z=12		
	System.out.println(x);	// 12	
	System.out.println(y);	// 10	
	System.out.println(z);	// 12	
	
	---------------
	
	int x = 4;
			 4	   6	 60		 
	int y = (x++)+(++x)+(x*10);		
	System.out.println("x="+x);	 // 6	
	System.out.println("y="+y);	 // 70	

6. 关系运算符(比较运算符)

  • 关系运算符有哪些? 分别有什么作用?
  • 其注意事项又是什么?
总结:	
	1.
        ==	判断2个数值是否相等!
        !=	判断2个数值是否不相等!
        >	判断第一个数值是否大于第二个数值
        >=  判断第一个数值是否大于或者等于第二个数值
        <	判断第一个数值是否小于第二个数值
        <=	判断第一个数值是否小于或者等于第二个数值
		结论:只要是进行关系运算符操作,得到的结果必定是一个boolean值!(要么是true,要么是false)
			一般用于我们的分支语句(if)
	2.
		在比较2个数值是否相等的情况下,不要将==写成了赋值运算符=,这样会改变程序原有的含义!
			int i = 10;
			int j = 20;
			int k = 10;
			System.out.println(i=j); // 进行赋值操作【将j的值赋值给i,然后打印i的值!】		

7. 逻辑运算符

  • 逻辑运算符用于链接boolean类型的表达式, 或者是值.
  • 逻辑运算符有哪些?
总结:
	逻辑与(&):2个条件全都满足,结果为true 【有false则false】  false & true 或者false & false
	逻辑或(|):2个条件只有有1个满足,结果就为true 【有true则true】
	逻辑异或(^):2个条件不同为true,相同为false
	逻辑非(!):取反 之前为true,逻辑非之后就为false;之前为false,逻辑非之后就为true

8. 短路逻辑运算符

  • &和&&的区别是?
总结: 
	逻辑与& 它两侧的表达式都会执行
	短路与&& 只要左侧的表达式为false,那么右侧的表达式就不会运行!【注定结果为false】
	提升代码的效率(性能)!
	
	int i = 10;
	int j = 20;
	System.out.println(++i>100 & j++>100); // i =11 ; j= 21
	System.out.println(++i>100 && j++>100); // i=11 ; j=20 【它没有被执行!】
  • |和||的区别是?
总结:
	逻辑或|:它两侧的表达式都会执行!
	短路或||:只要左侧的表达式的值为true,那么右侧的表达式就能不会执行!【注定结果为true】
	提升代码的效率(性能)!
  • 看程序写结果
int x = 3;
int y = 4;
System.out.println((++x < 2) && (y++ > 5));  
System.out.println("x:" + x);		// 	4		 
System.out.println("y:" + y);		//  4

9. 三元运算符 (三目运算符)

  • 三元运算符的格式为?
  • 其执行流程为?
总结:
	书写的格式:(关系运算符)?值1:值2;
		实例:int max = a>b?a:b;
	执行流程:
		如果关系运算符的结果为true,那么最终三元运算符的结果就是值1;否则最终结果为值2
    int a = 10;
    int b = 20;
    int min = (a < b) ? a : b;
    System.out.println(min); // 10
需求:获得3个数中的较大值
public class Demo06{
	public static void main(String[] args){
		// 需求:求3个数中的较大值!
		int x = 13;
		int y = 54;
		int z = 25;
		
		// 可以先获得前2个数的较大值,然后用这个较大值与第三个数进行比较
		//int temp = x>y?x:y; // 获得前2个数的较大值
		
		// 再用较大值与第三个数进行比较
		//int max = temp>z?temp:z;
		
		int max = (x>y?x:y)>z?(x>y?x:y):z;
		
		System.out.println("3个数中的较大值是:"+max);
	}
}

10. 三元运算符案例 - 两只老虎

  • 需求: 动物园里有两只老虎,已知两只老虎的体重分别为180kg、200kg,请用程序实现判断两只老虎的体重是否相同。
  • 代码实现:
public class Demo07{
	public static void main(String[] args){
		// 定义2个变量存储2只老虎的体重
		int height1 = 300;
		int height2 = 300;
		// 使用三元运算符进行比较【返回值类型取决于冒号左右的数据类型】
		String str = height1==height2? "相同" : "不相同";
		// 打印结果
		System.out.println("2只老虎的体重:"+str);
	}
}
  • 5分钟时间练习

11. 三元运算符案例 - 三个和尚

  • 一座寺庙里住着三个和尚,已知他们的身高分别为150cm、210cm、165cm,请用程序实现获取这三个和尚的最高身高。
  • 代码实现:
public class Demo08{
	public static void main(String[] args){
		// 定义3个变量记录3个和尚的身高
		int x = 150;
		int y = 210;
		int z = 165;
		
		// 可以先获得前2个数的较大值,然后用这个较大值与第三个数进行比较
		//int temp = x>y?x:y; // 获得前2个数的较大值
		
		// 再用较大值与第三个数进行比较
		//int max = temp>z?temp:z;
		
		int max = (x>y?x:y)>z?(x>y?x:y):z;
		
		System.out.println("3个和尚中的升高最高的是:"+max);
	}
}
  • 10分钟时间练习.

12. 数据输入

  • 为什么要有键盘录入?
    • 为了让程序更加的灵活,达到人机交互的效果
  • 如何实现键盘录入?
总结:
	1: 导包 (让Java已经写好的类和我们自己的类建立关联)
			import java.util.Scanner; // 必须放在类的上面!【固定写法!】

	2: 创建Scanner对象
			(创建一个用于键盘录入的机器)
			Scanner sc = new Scanner(System.in);// 除了sc可以更改,其余的都是固定写法!

	3: 调用nextInt方法, 进行键盘录入
			(调用机器中的功能, 进行键盘录入)
			int num = sc.nextInt();
/**
*	键盘录入数据:
		第一步:导包 import java.util.Scanner; (在类的上面完成)
		第二步:创建Scanner类的对象  Scanner scanner = new Scanner(System.in);
		第三步:给出一个有好的提示  System.out.println("请输入一个数字");
		第四步:获得用户输入的数字,使用一个变量来接收(存储)
		第五步:打印输出这个数字的值!
*/
// 1.导包在类的上面完成)
import java.util.Scanner;
public class Demo09{
	public static void main(String[] args){
		// 2.创建Scanner类的对象【scanner:变量名称】
		Scanner scanner = new Scanner(System.in);
		// 3.给出一个友好的提示信息
		System.out.println("请输入一个数字:");
		// 4.获得用户输入的数字,使用一个变量存储起来
		int num = scanner.nextInt();
		// 5.将用户键盘录入的数据打印在控制台
		System.out.println("用户之前输入的数据是:"+ num);
	}
}

13. 三个和尚升级版

  • 在获取三个和尚中的最高身高案例中,身高数据如果由键盘录入,该怎样实现呢
  • 代码实现:
import java.util.Scanner;

public class TestScanner {
	/*
		需求: 获取三个身高的最大值, 身高值通过键盘录入完成.
		
		分析:
			1. 键盘录入 -> Scanner操作的三个步骤
				A. 导包
				B. 创建Scanner对象(机器)
				C. 调用方法接受数据(调用机器中的功能)

			2. 使用键盘录入的三个变量, 进行比较
	*/
	public static void main(String[] args){
		// 创建Scanner对象
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入三个身高:");
		int num1 = sc.nextInt();
		int num2 = sc.nextInt();
		int num3 = sc.nextInt();
		
		// 使用键盘录入的三个变量, 进行比较
		int tempMax = (num1 > num2) ? num1 : num2;
		int max = (tempMax > num3 ) ? tempMax : num3;
		
		System.out.println("max=" + max);
	}
}
  • 10分钟时间练习.

14. 顺序结构

在Java中,程序执行有一定的顺序,总体分为三种执行结构:

​ 顺序结构:代码从上向下一行一行依次执行!

​ 选择结构(判断结构/分支结构):★★★★★

​ 循环结构:明天学习!

  • 什么是流程控制语句?
  • 流程控制语句的分类有哪些?
总结:
	1. 就是通过一些代码, 来[控制]程序的[执行流程].
			应用场景 :
				键盘接受一个年龄, 程序需要判断该年龄是否大于18岁, 如果大于18岁, 输出(可以进入网吧)
				否则, 给出提示, (不让进入网吧.)

	2.
		A. 顺序结构 : 所有Java程序默认的执行结构
							从上到下, 从左到右依次执行.

            main(){
                sop("1");
                sop("2");
            }
		B. 选择结构	:

						if 语句 (分支语句)

						switch 语句

									day03课程内容
		C. 循环结构
			day03课程内容

[外链图片转存失败(img-AFo8Ab4J-1563368754832)(C:/Users/Never Say Never/AppData/Roaming/Typora/typora-user-images/1563353497534.png)]

15. 分支结构 - if

  • if语句有几种格式?
  • 格式1该如何书写?
  • 其执行流程为?
总结:
	1. 单if语句:
		if(条件表达式){  // 条件表达式必定是一个boolean值
			语句体;     // 只有条件表达式的结果为true,才会执行语句体;
		}
		……				// 这里代码最后也会被执行!

	2. if...else语句:
		if(条件表达式){	// 条件表达式必定是一个boolean值
			语句体1;    // 只有条件表达式的结果为true,才会执行语句体1;
		}else{
			语句体2;    // 只有条件表达式的结果为flase,才会执行语句体2;
		}
		.... 其它代码
		
		// 1.导包在类的上面完成)
        import java.util.Scanner;
        public class Demo10{
            public static void main(String[] args){
                // 2.创建Scanner类的对象
                Scanner scanner = new Scanner(System.in);
                // 3.给出一个友好的提示信息
                System.out.println("请输入年龄:");
                // 4.获得用户输入的数字,使用一个变量存储起来
                int age = scanner.nextInt();

                System.out.println("今天天气不错,挺风和日丽的,我们明天不上课");

                // 5.判断
                if(age>=18){
                    System.out.println("可以进入网吧上网!");
                }else{
                    System.out.println("禁止未成年进入网吧!");
                }

                System.out.println("回家了……");
            }
        }
	
	3.if...else的扩展结构
		if(关系表达式1){
			语句体1;
		}else if(关系表达式2){
			语句体2;
		}else if(关系表达式3){
			语句体3;
		}
		  ....

		}else{
			语句体n;	
		}

  • 10分钟练习:
请定义两个int类型的变量,使用if语句判断两个变量的值是否相同,并输出结果。
public class Demo11{
	public static void main(String[] args){
		// 定义变量
		int num1 = 10;
		int num2 = 20;
		// 判断
		if(num1==num2){
			System.out.println("2个变量的值相同!");
		}else{
			System.out.println("2个变量的值不相同!");
		}
	}
}
  • 注意:
if语句如果控制的语句体, 是一条语句的话, 大括号可以省略不写, 但永远不建议省略.
	
	if(num1

16. if…else结构

  • 格式2
总结:

	if(比较表达式){
		语句体1;
	}else{
		语句体2;
	}


举例: 
	int score = 99;
	if(score==100){
		System.out.println("奖励100块钱");
	} else {
		System.out.println("挨顿揍");
	}

执行流程:
	
	1. 执行比较表达式
	2. 看其结果是true还是false

		true : 执行语句体1;
		false : 执行语句体2;
  • 10分钟练习:
    请定义两个int类型的变量a和b,使用if…else语句判断a的值是否大于b,并输出结果。

17. 案例 – 判断奇偶数

  • 键盘录入一个整数,请用程序实现判断该整数是奇数还是偶数
  • 示例代码:

分析:

​ 1.键盘录入,获取用户输入的数据(记录到一个变量num中)

​ 2.对数据进行判断

​ if(num%2==0){

​ // 说明是偶数

​ }else{

​ // 说明是奇数

​ }

import java.util.Scanner;
public class Demo12{
	public static void main(String[] args){
		// 创建键盘录入核心对象
		Scanner scanner = new Scanner(System.in);
		// 给出友好的提示信息
		System.out.println("请输入一个数字");
		// 调用Scanner的对象的方法获得键盘录入的数据
		int num = scanner.nextInt();
		
		// 判断
		if(num%2==0){
			// 说明是一个偶数
			System.out.println("数字 "+num+",它是一个偶数");
		}else{
			// 说明是一个奇数
			System.out.println("数字 "+num+",它是一个奇数");
		}
	}
}
  • 5分钟时间练习

18. if…else…if结构

  • A:格式3
总结:
	if(比较表达式1) {
		语句体1;
	}else if(比较表达式2) {
		语句体2;
	}else if(比较表达式3) {
		语句体3;
	}
	...
	else {
		语句体n+1;
	}


举例:
	if(考试考了100分){
		System.out.println("奖励100块钱");
	} else if(考试考了80) {
		System.out.println("奖励50块钱");
	} else if(考试考了60){
		System.out.println("这次就放过你");
	} else {
		System.out.println("挨顿揍");
	}
  • B:执行流程:
    * 首先计算比较表达式1看其返回值是true还是false,
    * 如果是true,就执行语句体1,if语句结束。
    * 如果是false,接着计算比较表达式2看其返回值是true还是false,
    * 如果是true,就执行语句体2,if语句结束。
    * 如果是false,接着计算比较表达式3看其返回值是true还是false,
    * 如果都是false,就执行语句体n+1。
  • C:注意事项:最后一个else可以省略,但是建议不要省略,可以对范围外的错误值提示
  • 8分钟时间练习
键盘录入一个星期数(1,2,...7),输出对应的星期一,星期二,...星期日

19. 案例- 考试奖励 [必掌握案例]

  • 需求:
    根据不同的考试成绩,给出不同的奖励
    95100分,自行车一辆;9094分,游乐场玩一次;
    80~89分,变形金刚玩具一个;80分以下,胖揍一顿。
  • 示例代码:

int score = sc.nextInt();

if(score>=95 && score<=100){

​ 自行车一辆

}else if(socre>=90 && score<=94){

​ 游乐场玩一次

}else if(socre>=80 && score<=89){

​ 变形金刚玩具一个

}else if score<80){

​ 胖揍一顿

}else{

​ 数据不合法

}

  • 10分钟时间练习.
今日内容小结:
	1.运算符:多个常量或者变量之间连接的符号我们称之为运算符!
	2.表达式:使用运算符将多个常量或者变量连接在一起就成为一个表达式
	3.运算符的分类:
		算术运算符、赋值运算符、关系运算符、逻辑运算符、三元运算符
		★★★★★问题:三元运算符可以与if进行相互改写,那么什么时候使用if,什么时候使用三元?
			如果判断中的语句代码特别多,适合使用if来编写(可读性较强!)
		
		作业:分别使用三元运算符和if语句来完成功能:求3个数中的较大值
	4.数据录入:
    	第一步:导包  import java.util.Scanner; // 必须放在类的上面
    	第二步:在main方法中创建一个Scanner类的对象  Scanner scanner = new Scanner(System.in);
		第三步:使用变量存储用户录入的数据  int num = scanner.nextInt();
	5.流程控制语句
    	★★★★★ 顺序结构:这是最简单的,从上向下逐行执行!
    	
    	★★★★★★★ 选择判断结构:、
    		if(关系表达式){
    			语句体;
    		}
    		
    		if(关系表达式){
    			语句体1;
    		}else{
    			语句体2;
    		}
    		
    		if(关系表达式){
    			语句体1;
    		}else if(关系表达式){
    			语句体2;
    		}else if(关系表达式){
    			语句体3;
    		}else{
    			语句体n;
    		}

今日目标

能够在程序中使用算术运算符进行算术运算

能够使用字符串连接符“+”进行字符串的拼接

System.out.println(1+‘a’+“itheima”+666); // 98itheima666

能够使用赋值运算符为变量赋值

理解自增/自减运算符的运算特点
能够使用关系运算符判断两个变量(值)的关系
能够使用逻辑运算符判断表达式是否成立
能够使用Scanner类接收键盘录入的数据
能够理解三种if语句的执行流程

可读性较强!)

	作业:分别使用三元运算符和if语句来完成功能:求3个数中的较大值
4.数据录入:
	第一步:导包  import java.util.Scanner; // 必须放在类的上面
	第二步:在main方法中创建一个Scanner类的对象  Scanner scanner = new Scanner(System.in);
	第三步:使用变量存储用户录入的数据  int num = scanner.nextInt();
5.流程控制语句
	★★★★★ 顺序结构:这是最简单的,从上向下逐行执行!
	
	★★★★★★★ 选择判断结构:、
		if(关系表达式){
			语句体;
		}
		
		if(关系表达式){
			语句体1;
		}else{
			语句体2;
		}
		
		if(关系表达式){
			语句体1;
		}else if(关系表达式){
			语句体2;
		}else if(关系表达式){
			语句体3;
		}else{
			语句体n;
		}

### 今日目标 ###

能够在程序中使用算术运算符进行算术运算

能够使用字符串连接符“+”进行字符串的拼接

System.out.println(1+'a'+"itheima"+666); //  98itheima666

能够使用赋值运算符为变量赋值

理解自增/自减运算符的运算特点
能够使用关系运算符判断两个变量(值)的关系
能够使用逻辑运算符判断表达式是否成立
能够使用Scanner类接收键盘录入的数据
能够理解三种if语句的执行流程

你可能感兴趣的:(Java 黑马最新29期基础班 第二天导师讲义,很适合初学者)