课程目录

  1. 面向对象的基本概念
  2. 类和对象
  3. 类和对象的定义格式
  4. 对象与内存分析
  5. 封装性
  6. 构造方法
  7. this关键字
  8. 值传递与引用传递
  9. 对象的一对一关系
  10. static关键字
  11. main方法分析
  12. 代码块
  13. 单例设计模式
  14. 对象数组与管理

1.面向对象基本概念

面向对象思维方式:先整体后集体先抽象后具体。
如何学习面向对象:
1.掌握一门面向对象语言的语法
2.熟悉面向对象的设计原则
3.熟悉慢性单纯的设计模式

2.类与对象

什么是类?
1.类是:分类 类别
2.通过分类,我们可以区别不同的事物种类,在日常生活中,我们常常这样做
3.所以,类是一组具有相同特性(属性)与行为(方法)的事物集合

类与对象的关系
1.类表示一个共性的产物,是一个综合的特征,而对象,是一个个个性的产物,是一个个个体的特征。
2.类由属性和方法组成
属性:就相当于一个个的特征
方法:就相当于人的一个个行为,例如:唱,跳,rap,蓝球

3.类和对象的定义格式

定义一个类

class类名称{
属性名称;
返回值类型 方法名称(){}

对象的定义:
一个类要想真正的进行操作,则必须依靠对象,对象的定义格式如下:

类名称 对象名称=new 类名称();

在Java中,对象声明有两种含义

声明对象:Horse horse=null;

表示声明了一个对象,但是此对象无法使用,horse没有具体的内存指向

实例化对象:horse=new Horse();

//表示实例化了对象,可以使用
按照以上方式就能产生对象了

如果要想访问类中的属性或者方法(方法的定义),
可以依靠以下的语法形式:
访问类中的属性

对象 . 属性;

调用类中的方法:

对象 . 方法();

通过对象调用方法:

horse.eat();

匿名对象调用方法
new Horse().eat();

package test;public class test{public static void main(String[] args){Horse h=null;//声明一个变量(除了八种基本数据类型外,都是引用数据类型,包括数组)//创建一个Horse类型的对象,实例对象h=new Horse();//有了对象,我们就可以调用对象的属性和方法h.name="赤兔马";h.age=30;h.run();//调用方法,那么方法就会被执行。h.eat();                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            //匿名对象,只能使用一次,用完后,该对象就会被释放new Horse().eat();h=null;//把对象释放//h.eat();//当对象不存在时,调用该对象的属性和方法将报错(空指针)}
}//自定义一个类(类型)
class Horse{//在类中定义属性String name;int age;public void run(){System.out.println("马跑步"+name);}public void eat(){System.out.println("我吃草");}}

4.对象内存分析

1.new关键字表示创建一个对象
2.new关键字表示实例化一个对象
3.new关键字表示申请 内存空间

注意:如果使用一个没有申请内存空间的对象,会报空指针异常

java.lang.NullPointerException
栈内存存放类型名,存放基本数据类型
堆内存存储对象用的

1.在栈内存中存个变量名
2.语句二表示在堆内存中new一块区域用来存放属性和方法,并把地址存在栈内存中


注意,此时“小白”仅仅是地址,2这样写是为了方便看。


声明两个对象,一个实例化一个没有实例化

对象之间的赋值

注意:如果我更改了horse1.name,那么horse2.name也会改变,同理也是这样。因为他俩指向同一个内容

注意:当horse2=horse1;后对horse2.name改,horse1.name也会改,因为指向的地址相同。

类与对象小结

  1. new关键字:表示向内存申请空间,也表示实例化一个对象,创建一个对象。
  2. 一个对象在内存中的大小,由该对象的所有属性所占的内存大小的总和,引用类型变量在32位系统上占4个字节,在64位系统上占8个字节加上额外的对象隐形数据所占的大小。(String字符串是引用类型变量,不是基本数据类型变量
  3. 相同的类型才可以赋值
  4. 不同的引用,指向同一个对象,任何一个引用改变对象的值,其他引用都会反映过来
  5. 当一个堆中的对象没有被任何引用变量所指向时,该对象会被JVM的GC程序认为是辣鸡对象,从而被回收。
  6. 编程时要注意的问题:在确定不使用对象时,要尽早释放对象:引用=null//匿名对象,只能使用一次,用完后,该对象就会被释放如:

new Horse().eat(); h=null;//把对象释放

5.封装性

封装性的概念
1.封装性是面向对象思想的三大特征之一。
2.封装就是隐藏实现细节,仅对外提供访问接口
封装有:类的封装,属性的封装,方法的封装,组件的封装,模块化封装,系统级封装…

封装的好处
1.模块化
2.信息隐藏
3.代码重用
4.插件化易于调试
5.具有安全性

封装的缺点会影响执行效率

package test;public class test{public static void main(String[] args){//未封装之前,可以直接调用Person p1=new Person();p1.name="feifei";p1.age=18;}
}/*封装性*/
//没有封装之前
class Person{//属性的封装String name;int age;
}

如果属性没有封装,那么在本类之外创建对象后,可以直接访问属性
private关键字:访问权限修饰符,public表示共有的,private表示私有的。私有的属性或者方法,只能在本类中访问,共有的属性或者方法,可以被类外的其他类访问。想要早类外部访问私有属性,我们需要提供共有的方法来间接访问
通常在一个类中,属性都私有化,并对外体提供getter and setter 方法

封装后

class Person{//加上private,封装属性private String name;private int age;
}

//未封装之前,可以直接调用
Person p1=new Person();
p1.name=“feifei”;
p1.age=18;

想要类外部访问私有属性,我们需要提供共有的方法来间接访问

//封装之后调用
Person p1=new Person();
p1.setName(“feifei”);
p1.setAge(18);

package test;public class test{public static void main(String[] args){//封装之后调用Person p1=new Person();p1.setName("feifei");p1.setAge(18);}
}/*封装性*/
//没有封装之前
class Person{//属性的封装private String name;private int age;//getter and setter
//对外提供一个为name属性设值方法
public void setName(String name){this.name=name;//等号后面的name为括号内参数name,this后name为class的属性name}
//对外提供一个获取name属性的方法
public String getName(){return name;
}
public void  setAge(int age){this.age=age;
}
public int getAge(){return age;}
}

6.构造方法

什么是构造方法

构造方法的定义
构造方法是在类中定义的,构造方法的定义格式:方法名称与类名称相同,无返回值类型的声明:

public Dog();{}

对象的实例化语法:

Dog dog=new Dog(); //Dog后面有个括号,带括号表示调用了方法,此时调用的方法就是构造方法了

1.构造方法就是类构造对象的时候调用的方法,用于对象的初始化工作
2.构造方法是实例化一个类的对象时,也就是new的时候,无需像普通方法对象名.方法名。最先调用的方法。
3.新手在刚开始
很容易将class定义到main函数中
*。造成Java出现No enclosing instance of type E is accessible. Must qualify the allocation with an enclosing

构造方法的调用:

Dog dog =new Dog();
//new的过程中默认调用了dog()构造方法;
Dog dog1=new Dog(“旺旺”,18);

package test;import java.util.Arrays;
import java.util.Random;public class test2 {public static void main(String[] args) {Dog dog =new Dog();//new的过程中默认调用了dog()构造方法;Dog dog1=new Dog("旺旺",18);}}
//构造方法是在类中定义的;/class Dog {// 方法名称与类名称相同// 注意:无返回值类型的声明,不要写void//无参构造方法为默认,可以不写,前提是后面还有构造方法public Dog() {System.out.println("构造方法已经调用了");}//重载构造方法,无返回值类型声明,不写voidpublic Dog(String name,int age){this.name=name;this.age=age;System.out.println("带两个参数的构造方法执行了");   }private String name;private int age;public void setName(String name){this.name=name;}public String getName(){return name;}public void setAge(int age){this.age=age;}public int getAge(){return age;}}

构造方法的重载
无参构造方法:
public Dog(){}
带一个参数的构造方法:
public Dog(String name){
this .name=name;
}
带多个参数的构造方法:
public Dog(String name,int age){
this .name=name;
this.age=age;
}

构造方法A如何调用构造方法B
this(方法B名字);

构造方法小结

7.this关键字

在Java基础中,this关键字是一个非常重要的概念。使用this关键字可以完成以下操作:

  • 调用类中的属性
  • 调用类中的方法或构造方法
  • 表示当前对象

调用类中的属性
谁调用我,谁就是当前对象。谁就是this,代码中是cat
调用类中的方法或构造方法
补充:this前面可以加上类名.this。在后面的内部类知识中可能会涉及到。

8.值传递和引用传递

知识回顾:成员变量与局部变量的区别
示例一:值传递

package test;public class test2 {public static void main(String[] args) {int x = 10;method(x);System.out.println("x=" + x);}public static void method(int mx) {mx = 20;}
}

运行结果X=10;为啥不是20呢

因为x和mx 都是在方法中定义的,都存储在栈内存中,只是mx被赋值成了20。 Java都是值传递。X并没有变化
示例二:引用传递

package test;
public class test2 {public static void main(String[] args) {Duck d=new Duck();menthod(d);System.out.println("鸭子的年龄是"+d.age);;}public static void menthod(Duck duck){duck.age=5;}
}
class Duck{int age=2;//省略封装
}

运行结果:鸭子的年龄是5,注意,new操作后,栈内存存的是d的地址、且class Duck后存的是成员变量,放在对内存中
当变量存的是地址的时候,操作就是引用传递。
当变量存的是值的时候,操作就是值传递。
示例三:String类型传递

package test;
//字符串本身就是一个对象
public class test2 {public static void main(String[] args) {String name ="小飞";method(name);System.out.println("名字是"+name);}public static void method(String sname){sname="小贝";}
}

String的值储存在堆内存当中,一个字符串相当于new一个对象出来。字符串本身就是一个对象
在String 中有两个对象出现。”“小飞”和“小贝”
示例四:还是String传递

package test;
public class test2 {public static void main(String[] args) {Person p=new Person();menthon(p);System.out.println("人名是"+p.name);}public static void menthon(Person per ){per.name="贝贝";}
}
class Person{String name ="飞飞";//省略封装
}

输出结果:人名是贝贝
注意:String是引用型数据变量,String name 表示在堆内存中开辟一块内存存储的是name的地址。=“飞飞”表示在这块地址上命名

除了基本数据类型在栈内存完成之外,其余的都在堆内存完成。
自己画图画几遍

9.对象的一一对应关系

两个对象之间一一对应关系:
比如:
一个英雄(hero)对一个兵器(weapon)代码如何表示?

补充说明
要注意Weapon weapon和 Weapon wepon = new Weapon() 的区别

前面讲的是声明一个变量,变量名为weapon,变量类型为Weapon 后面讲的是创建一个Weapon 对象,并把它赋给了变量wepon。也就是说wepon 实际上引用了一个Weapon 类型的对象
其实类名不是作为数据类型,只能说将这个类的对象作为返回值。意思就是说,这个方法的返回值不是普通的数据类型,而是一个类对象。这样做可以避免一个方法要返回N多的数据,比如说,你要同一个方法中得到name和age,但是java又不能返回多个值,除了可以使用一个字符串或者字符串数组存放外,我们可以定义一个Student对象,对象中包含name和age属性,这样就可以用这个对象把属性封装起来以及方法,一起返回。

1.在hero类定义一个Weapon类型的weapon ,(在本类中定义一个对方方法)
2.设置weapon的getter and setter方法,单项一对一,若双向可在weapon类同样设置
3.关联起来

//双向一对一,英雄得到他的兵器,反过来兵器也能得到他的英雄
//单向一对一,英雄捡到兵器,兵器不知道英雄
package test;
public class test{public static void main(String[] args){Hero hero =new Hero("刘备",18);Weapon weapon=new Weapon("剑",3);//把两个对象关联起来hero.setWeapon(weapon);weapon.setHero(hero);String name=hero.getName();int age=hero.getAge();Weapon w=hero.getWeapon();System.out.println("我是"+name+",我"+age+"岁,武器是"+w.getName()+",等级是"+w.getGrade());}

百度谷歌了一下相关资料。原来我写的内部类是动态的,
也就是开头以public class开头。
而主程序是public static class main。
在Java中,类中的静态方法不能直接调用动态方法。
只有将某个内部类修饰为静态类,然后才能够在静态类中调用该类的成员变量与成员方法。
所以在不做其他变动的情况下,
最简单的解决办法是将public class改为public static class.

//通过英雄来获取它的信息
//英雄类

public static class Hero{private String name;private int age;private Weapon weapon;//在本类中定义一个其他类类型的私有变量//一对一对应关系//设置getter and setter方法public void setWeapon(Weapon weapon){this.weapon=weapon;}public Weapon getWeapon(){return weapon;}public Hero(){}public Hero(String name,int age){this.name=name;this.age=age; }public void setName(String name){this.name=name;}public String getName(){return name;}public void setAge(int age){this.age=age;}public int getAge(){return age;}
}

//武器类

public static class Weapon{private String name;private int grade;private Hero hero;//设置Hero类型的hero;//设置getter and setter 方法public void setHero(Hero hero){this.hero=hero;}public Hero getHero(){return hero;}public Weapon(){}public Weapon(String name,int grade){this.name=name;this.grade=grade;}public void setName(String name){this.name=name;}public String getName(){return name;}public void setGrade(int grade){this.grade =grade;}public int getGrade(){return grade;}}}

10.static关键字

static关键词的作用:
1.使用static关键词修饰一个属性
声明位static的变量实质上是全局变量(生命周期变长了,从程序启动到程序结束)
2.使用static关键字修饰一个方法
通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法
3.使用static关键字修饰一个类(普通类不能用static,只有内部类才能用static)

static关键字总结
1.静态对象或方法不属于对象,依赖类。
2.静态变量是全局变量,生命周期从类被加载后一直到程序结束
3.静态变量只有存一份,在静态方法区存储
4.静态变量是本类所有对象共享一份
5.建议不要使用对象名去调用静态数据,直接使用类名调用
6.static修饰一个方法,那么该方法属于类,不属于对象,直接用类名调用。意味着没有创建对象也能用
7.静态方法不能访问非静态的数据,只能访问静态。this和super都无法出现在static 修饰的方法中

package test;
public class test{public static void main(String[] args){//Role beibei=new Role("刘备","蜀国");//Role yuanchuang =new Role("云长","蜀国");//Role feifei =new Role("张飞","蜀国");Role beibei=new Role("刘备");Role yuanchuang =new Role("云长");Role feifei =new Role("张飞");System.out.println(beibei.getInfo());System.out.println(yuanchuang.getInfo());System.out.println(feifei.getInfo());System.out.println("-------静态变量是本类所有对象共享一份-------");beibei.country="晋朝";System.out.println(beibei.country);System.out.println(yuanchuang.country);System.out.println(feifei.country);System.out.println("-------建议不要使用对象名去调用静态数据,直接使用类名调用-------");beibei.country="汉朝";System.out.println(Role.country);//因为country是静态属性,所以可以用类名点属性System.out.println(Role.country);System.out.println(Role.country);}
}

//角色

class Role{private String name;//private String country;不想写三个蜀国所以:static String country="蜀国";//静态变量(全局变量)public Role(String name,String country){this.name=name;this.country=country;}//去掉country,可行public Role(String name){this.name=name;}public void setName(String name){this.name =name;}public String getName(){return name;}//静态方法不能访问非静态的数据public static void setCountry(String country){//this.country=country;//Cannot use this in a static context//意思是:this关键字不能在static静态方法中使用,具体解释看下文Role.country=country;}public String getInfo(){return "名字:"+name+",国家:"+country;}
}

方法加了static,就会有静态方法区

Cannot use this in a static context 因为:

Static方法是类方法,先于任何的实例(对象)存在。即Static方法在类加载时就已经存在了,但是对象是在创建时才在内存中生成。而this指代的是当前的对象

举个例子:

public class Test {private static int n = 0;public static void setNum(int n) {this.n = n;  //Cannot use this in a static context}public static void main(String[] args) {setNum(0);}
}

在方法中定义使用的this关键字,它的值是当前对象的引用.也就是说你只能用它来调用属于当前对象的方法或者使用this处理方法中成员变量和局部变量重名的情况.

而且,更为重要的是this和super都无法出现在static 修饰的方法中,static 修饰的方法是属于类的,该方法的调用者可能是一个类,而不是对象.如果使用的是类来调用而不是对象,则 this就无法指向合适的对象.所以static 修饰的方法中不能使用this.


声明为static的方法有以下几条限制:

  • 它们仅能调用其他static方法
  • 它们只能访问static数据
  • 它们不能以任何方式引用super或this

所有对象共同的属性或者方法,那么我们可以定义为静态的。

11.main方法分析

主方法:
public static void main (String[ ] args){
//代码块
}
public:公有的,最大的访问权限
static:静态的,无需创建对象
void:表示没有返回值,无需向jvm返回结果
main:方法名,固定的方法名
String[ ] args:表示参数位字符串数组,可以在调用方法时传入参数

12.代码块

  1. 普通代码块
    直接写在方法中的代码块就是普通代码块
  2. 构造块
    是在类中定义的代码块,new创建对象时即被调用(构造方法也是new后即调用),优于构造方法执行
  3. 静态代码块
    在类中使用static声明的代码块称为静态代码块
    在第一次使用的时候被调用(创建对象),只会执行一次,优于构造块执行,我们在项目开发中,通常会使用静态代码块来初始化只调用一次的数据。比如说:读取配置文件
  4. 同步代码块(多线程中讲解)

小结:重点使用的顺序是静态代码块,普通代码块,同步代码块,构造代码块

package test;
public class test{public static void main(String[] args){Student s=new Student(); //构造块是在类中定义的代码块,//    new创建对象时即被调用优于构造方法执行System.out.println("-------------");Student s1=new Student();}
}class Student{Student(){System.out.println("我是构造方法,顺序排第一,却最后执行");}{System.out.println("我是构造代码块,我排第二,我比构造方法先执行");}static{System.out.println("我是静态代码块,我排最后 ,但我第一个执行。只能执行一次");}public void study(){System.out.println("我是最普通的代码块");}
}

执行结果:

13.单例设计模式

单例设计模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

  1. 构造方法私有(private)化,里面什么都不要写
  2. 创建一个本类静态对象
  3. 给外部提供一个公共的静态的方法getInstance(),用来获取对象实例

两种实现方式:

  1. 饿汉式:在类被加载后,对象立马被创建,到程序结束后释放。占用内存时间长,效率高
  2. 懒汉式:在第一次调用getInstance方法时,对象被创建,到程序结束后被释放。占用内存时间短。效率低(懒加载,延迟加载)

代码:

package test;
public class test{public static void main(String[] args){Singleton1 s1=Singleton1.getInstance();s1.print();Singleton2 s2=Singleton2.getInstance();s2.print();}
}
//饿汉式:占用内存时间长,效率高
class Singleton1{//1.构造方法私有化,里面什么都不要写Singleton1(){}//2.创建一个本类静态私有化对象private static Singleton1 s=new Singleton1();//3.给外部提供一个公共的静态的方法,用来获取对象实例public static Singleton1 getInstance(){return s;}public void print(){System.out.println("测试用其他的方法1");}
}
//懒汉式:占用内存时间短。效率低(懒加载,延迟加载)
//在多线程访问时会有安全问题
class Singleton2{private Singleton2(){}//懒,并没有定义对象出来private static Singleton2 s;public static Singleton2 getInstance(){if(s==null){s=new Singleton2();}return s;}public void print(){System.out.println("测试用其他方法2");}}

在项目中为什么要使用单例,单例有什么好处?

  1. 在设计一些工具类的时候(通常工具类,只有功能方法,没有属性)
  2. 工具类可能会被频繁调用
  3. 可以节省重复创建对象所带来的内存消耗,从而提高效率

能不能使用构造方法私有化+静态方法来替代单例?
格式:
如果使用构造方法私有化+静态方法来实现工具类。那么静态方法会存在方法区,加载之后就会存在,调用方便
如果使用构造方法单例,方法是普通方法,依赖对象实现。运行过程中如果方法中有参数需要进栈出栈。内存占用小。

14.对象数组与管理

点击鸡舍管理系统

Java听课笔记7(面向对象 上)相关推荐

  1. java听课笔记8面向对象(下)

    课程大纲 继承的基本概念 继承的限制 子类的实例化过程 方法的重写 super 关键字 继承的应用示例 final关键字 抽象类 接口 多态性 instanceof关键字 抽象类应用-模版方法模式 接 ...

  2. Java学习笔记基础(上)

    写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java语言代码把思路体现出来. 学习新技 ...

  3. JAVA学习笔记之面向对象(一)

    作为初入开发的萌新,我根据黑马程序员的教学视频和课件整理总结,记录下自己的JAVA学习,方便巩固和交流.每篇笔记首先回顾知识点,然后贴上代码和执行结果,最后进行小结.若有不正之处或者有疑问,欢迎指出, ...

  4. 【原】Java学习笔记020 - 面向对象

    1 package cn.temptation; 2 3 public class Sample01 { 4 public static void main(String[] args) { 5 // ...

  5. java听课笔记(六)

    面向对象 对象的概念 什么是对象 一切客观存在的事物都是对象 对象组成 属性,方法 类 描述同类对象的共有的属性和方法 类是创建对象的模板 全局变量 实例变量 有默认值,引用类型是null,基本 局部 ...

  6. 初二计算机听课笔记,初二物理上听课记录20篇

    初中物理应讲究教与学.讲与练.主导与主体.学知识与学做人.学知识与提高能力.全面要求与因材施教等这都是在课堂教学中引出,在课堂教学中展开,又在课堂教学中运行,以何种形式来优化就可能带来不同的教学效果. ...

  7. Java学习笔记:04面向对象-内部类_访问修饰符_final

    04面向对象-内部类/访问修饰符/final 1.static的介绍 static:关键字,静态的 static的作用是用来修饰类中的成员 2.访问一个类中的某一个成员变量 方法一: _1.创建对象 ...

  8. 【原】Java学习笔记018 - 面向对象

    1 package cn.temptation; 2 3 public class Sample01 { 4 public static void main(String[] args) { 5 // ...

  9. java听课笔记(十五)之 网络编程

    网络编程 网路应用的结构 TCP编程 TCP是一个有连接,可靠的协议 java.net.Socket java.net.ServerSocket 核心思路 开发服务器端 ServerSocket ss ...

最新文章

  1. python合并多个excel为一个_Python合并多个Excel数据
  2. mysql tags_mysql tags table解决方法
  3. 微服务系列:MicroProfile和Apache TomEE
  4. ORA-12514: TNS:监听程序当前无法识别连接描述符中请(转)
  5. nsga2算法c++实现_Bellman-Ford算法
  6. ffmpeg2.8将多媒体文件保存为ppm
  7. python(7)– 类的反射
  8. Delphi Open Tools Api实例研究(一)
  9. nagios 163邮件报警
  10. 开始新的学习之旅--PHP开发学习--基础部分笔记
  11. 从零实现深度学习框架——Softmax回归简介
  12. 戴文的Linux内核专题:08内核配置(4)
  13. ITIL-IT运维管理-概述
  14. @media scree 手机移动端屏幕自适应
  15. 神经网络权重是什么意思,bp神经网络怎么看结果
  16. ceph BALANCER
  17. 解决退格键在MinGW的vim中不起作用的问题
  18. 2. Spring早期类型转换,基于PropertyEditor实现
  19. 陕西中际现代:基于自适应算法的PLC滴灌控制系统
  20. DSShop单店铺商城B2C功能列表清单

热门文章

  1. 国产飞腾安装Python依赖库
  2. Log4j的扩展-支持设置最大日志数量MaxFileSize的DailyRollingFileAppender
  3. 腾讯云服务器网页存在哪里找,腾讯云 AMD服务器入口在哪里?
  4. leetcode 判断链表是否有环
  5. unity中怎么做河流_unity3d怎么绘制海洋河流湖泊并添加水面倒影?
  6. c语言用指针实现日期输出,C语言指针实现链表以及用gcc编译输出
  7. c mysql maxpoolsize_记一次 druid maxPoolSize(maxActive) 配置引起的线上事故
  8. 自学成才的计算机科学家的10本书
  9. [益智]:桌子上放置硬币
  10. 企业拥抱Windows 8的十大理由