【原】Java学习笔记016 - 面向对象
1 package cn.temptation; 2 3 public class Sample01 { 4 public static void main(String[] args) { 5 // this 关键字 的使用 6 7 Student student = new Student(); 8 student.setName("张三"); 9 System.out.println(student.getName()); 10 } 11 } 12 13 // 学生类 14 class Student { 15 // 成员变量 16 private String name; 17 18 // 构造函数 19 20 // 成员方法 21 // 因为觉得参数叫name这个变量名比较好听,setXXX方法中形参也想使用name这个变量名,可以么? 22 // public void setName(String studentName) { 23 // name = studentName; 24 // } 25 26 public void setName(String name) { 27 // 产生警告:The assignment to variable name has no effect 28 // 这里就搞不清楚了,到底是把成员变量的name赋值给了形参的name,还是把形参的name赋值给了成员变量的name? 29 // 回想一下 对象名.成员变量 或者 对象名.成员方法,在这里把形参的name赋值给了成员变量的name 30 // 也就是说下句中前面的name如果能标明是成员变量的name就没有问题了 31 // name = name; 32 33 // 考虑在setXXX方法中创建一个对象,把形参的name赋值给创建出来的对象的成员变量name,但是这样写还是有问题的 34 // 因为在setXXX方法中创建出的这个对象 和 主函数中创建的对象不是一个对象,主函数中创建的对象获取其成员变量时还是得到默认值null的 35 // Student student = new Student(); 36 // student.name = name; 37 38 // 使用 this 关键字,表明把形参的name赋值给当前这个对象的成员变量name,这个this指的就是当前的这个对象 39 // 通过设置断点查看到,下句的this的值为:cn.temptation.Student@7fbe847c 40 // 和主函数中创建出的对象值为:cn.temptation.Student@7fbe847c 相同 41 this.name = name; 42 43 // 注意: 44 // 上句中赋值号右侧的name根据变量调用原则:就近原则,就近找到了局部变量name的定义,它是局部变量 45 // 赋值号左侧的name根据this这个当前对象的点号运算符访问到了成员变量name 46 } 47 48 public String getName() { 49 // 下句中的name根据变量调用原则:就近原则,所以其为成员变量 50 // return name; 51 52 // 下句的name根据this这个当前对象的点号运算符访问到了成员变量name,效果和上句相同 53 return this.name; 54 } 55 }
1 package cn.temptation; 2 3 public class Sample02 { 4 public static void main(String[] args) { 5 // 通过IDE自动生成getXXX和setXXX方法 6 // 方式1:alt+shift+s、alt+shift+r 7 // 方式2:菜单项或右键,找到Source,再找到Generate getters and setters... 8 9 // 通过IDE自动生成构造函数 10 // 方式1:alt+shift+s、alt+shift+o 11 // 方式2:菜单项或右键,找到Source,再找到Generate constructor using Fields... 12 } 13 } 14 15 // 员工类 16 class Employee { 17 // 成员变量 18 private String name; 19 private int age; 20 21 // 构造函数 22 public Employee() { 23 24 } 25 26 public Employee(String name, int age) { 27 this.name = name; 28 this.age = age; 29 } 30 31 // 成员方法 32 public String getName() { 33 return name; 34 } 35 36 public void setName(String name) { 37 this.name = name; 38 } 39 40 public int getAge() { 41 return age; 42 } 43 44 public void setAge(int age) { 45 this.age = age; 46 } 47 }
1 package cn.temptation; 2 3 public class Sample03 { 4 public static void main(String[] args) { 5 // Person person1 = new Person(); 6 // person1.setName("张三"); 7 //// person1.setCountry("中国"); 8 // System.out.println("姓名为:" + person1.getName() + ",国籍为:" + person1.getCountry()); 9 // 10 // Person person2 = new Person(); 11 // person2.setName("李四"); 12 //// person2.setCountry("中国"); 13 // System.out.println("姓名为:" + person2.getName() + ",国籍为:" + person2.getCountry()); 14 15 // 发现问题:创建了若干个Person对象,他们的country这个成员变量都是"中国",需要进行很多次setCountry赋值 16 // 对于一系列对象具有相同的成员变量值,是否有便捷的处理方式? 17 // 方式1、对成员变量使用指定的默认值,方法可行 18 // 方式2、既然是描述一系列对象的相同的成员变量值,换句话说就是对象们的成员变量值,再抽象一步,对象们的抽象----->类 19 20 // 引入静态的概念:static 关键字 21 // static关键字可以用于成员变量 和 成员方法。用在成员变量上,成员变量就是静态成员变量;用在成员方法上,成员方法就是静态成员方法。 22 23 // static的格式: 24 // 静态成员变量: static 数据类型 变量名; 25 // 静态成员方法:修饰符 static 返回类型 方法名(参数列表) { ... } 26 27 // 使用static修饰成员变量后,对某一个对象设置了静态成员变量的值,其他没有被设置静态成员变量的对象也具有了相同的值(注意:对象们的含义) 28 // Person person3 = new Person(); 29 // person3.setName("王五"); 30 // person3.country = "中国"; 31 // System.out.println("姓名为:" + person3.getName() + ",国籍为:" + person3.country); 32 // 33 // Person person4 = new Person(); 34 // person4.setName("赵六"); 35 // System.out.println("姓名为:" + person4.getName() + ",国籍为:" + person4.country); 36 37 // 使用static修饰成员变量后,使用 类名.静态成员变量名 可以访问到静态成员变量,可以不创建对象 38 // Person.country = "中国"; 39 // 40 // // 再创建对象,对象的静态成员变量的值 等同于使用 类名.静态成员变量 设置的值 41 // Person person5 = new Person(); 42 // person5.setName("钱七"); 43 // // 下面两句效果相同 44 // System.out.println("姓名为:" + person5.getName() + ",国籍为:" + person5.country); 45 // System.out.println("姓名为:" + person5.getName() + ",国籍为:" + Person.country); 46 // 47 // Person person6 = new Person(); 48 // person6.setName("王八"); 49 // // 下面两句效果相同 50 // System.out.println("姓名为:" + person6.getName() + ",国籍为:" + person6.country); 51 // System.out.println("姓名为:" + person6.getName() + ",国籍为:" + Person.country); 52 } 53 } 54 55 //// 人类 56 //class Person { 57 // // 成员变量 58 // private String name; 59 //// private String country; 60 //// private String country = "中国"; 61 // public static String country; 62 // 63 // // 成员方法 64 // public String getName() { 65 // return name; 66 // } 67 // 68 // public void setName(String name) { 69 // this.name = name; 70 // } 71 // 72 //// public String getCountry() { 73 //// return country; 74 //// } 75 //// 76 //// public void setCountry(String country) { 77 //// this.country = country; 78 //// } 79 //}
1 package cn.temptation; 2 3 public class Sample04 { 4 public static void main(String[] args) { 5 // static的特点: 6 // 1、static修饰的成员伴随着类被类加载器(classloader)加载而加载的 7 // 2、static修饰的这些成员变量 和 成员方法,出现的时间比对象要早(理解:只要是在大陆出生的,还没出生就确定了你的国籍是中国的) 8 // 3、static描述的是类的特征 和 行为,也是对象们都具有的特征 和 行为 9 // 4、static使用时,可以使用 对象名.静态成员,也可以使用 类名.静态成员,建议使用 类名.静态成员 10 11 // 类名.非静态成员变量,产生语法错误 12 // 语法错误:Cannot make a static reference to the non-static field Test.i 13 // System.out.println(Test.i); 14 // 对象名.非静态成员变量,语法正确 15 // Test test = new Test(); 16 // System.out.println(test.i); 17 // 18 // // 类名.静态成员变量,语法正确 19 // System.out.println(Test.j); 20 // 21 // Test.j = 4; 22 // 23 // Test testEx = new Test(); 24 // // 对象名.静态成员变量,语法正确 25 // System.out.println(testEx.j); 26 // // 类名.静态成员变量,语法正确(推荐写法) 27 // System.out.println(Test.j); 28 } 29 } 30 31 //class Test { 32 // int i = 2; 33 // static int j = 3; 34 //}
1 package cn.temptation; 2 3 public class Sample05 { 4 public static void main(String[] args) { 5 // 成员变量设置为static,其相应的封装方法也需要设置为static,否则静态成员变量在类加载时就被加载的,却因为对应的封装方法不是static的而无法使用 6 // Baby.setCountry("中国"); 7 // 8 // Baby baby = new Baby(); 9 // baby.setName("张三"); 10 // System.out.println("姓名为:" + baby.getName() + ",国籍为:" + Baby.getCountry()); 11 } 12 } 13 14 //class Baby { 15 // // 成员变量 16 // private String name; 17 // private static String country; 18 // 19 // // 成员方法 20 // public String getName() { 21 // return name; 22 // } 23 // 24 // public void setName(String name) { 25 // this.name = name; 26 // } 27 // 28 // public static String getCountry() { 29 // return country; 30 // } 31 // 32 // public static void setCountry(String country) { 33 // // 明确显示的指出把局部变量形参赋值给 类名.静态成员变量 34 // Baby.country = country; 35 // 36 // // 语法错误:Cannot use this in a static context 不能在一个static上下文环境中使用this 37 // // 这里为什么不能使用this? 答:因为this指的是当前这个对象,既不是对象们,也不是类 38 //// this.country = country; 39 // } 40 // 41 //}
1 package cn.temptation; 2 3 public class Sample06 { 4 public static void main(String[] args) { 5 // static关键不但可以用在成员变量上,也可以使用在成员方法上 6 7 // 访问性问题 8 /* 9 * 1、静态成员方法 10 * 只能访问静态的成员变量 和 静态的成员方法 11 * 不能访问非静态的成员变量 和 非 静态的成员方法 12 * 2、非静态成员方法 13 * 能访问静态的成员变量 和 静态的成员方法 14 * 能访问非静态的成员变量 和 非 静态的成员方法 15 * 16 * 总结: 静态的只能访问静态的,非静态的都可以访问 17 */ 18 } 19 } 20 21 class Demo { 22 // 成员变量 23 // 非静态的成员变量 24 int i = 2; 25 // 静态的成员变量 26 static int j = 3; 27 28 // 成员方法 29 // 非静态的成员方法 30 public void method1() { 31 System.out.println(i); 32 System.out.println(j); 33 34 method2(); 35 method3(); 36 } 37 38 public void method2() { 39 40 } 41 42 // 静态的成员方法 43 public static void method3() { 44 // 语法错误:Cannot make a static reference to the non-static field i 45 // System.out.println(i); 46 System.out.println(j); 47 48 // 语法错误:Cannot make a static reference to the non-static method method1() from the type Demo 49 // method1(); 50 method4(); 51 } 52 53 public static void method4() { 54 55 } 56 }
1 package cn.temptation; // 在命令行窗口下编译执行,这句先注释掉 2 3 public class Sample07 { 4 public static void main(String[] args) { 5 // main主函数(主方法) 6 // 1、public:公开的,可访问权限最大 7 // 2、static:静态的,静态的main方法被JVM调用(因为这个main方法是Java程序的入口),调用会是一种什么形式? 8 // 形式1、Sample07 对象名 = new Sample07(); 对象名.main(); 9 // 形式2、Sample07.main(); 10 // 调用时,JVM自然不会先去创建一个Sample07对象的,必然是形式2,形式2需要成员方法使用static修饰,所以main主函数使用static关键字修饰 11 // 3、void:无返回的,JVM不需要返回什么 12 // 4、main:使用main作为主函数的方法名是一种约定 13 // 5、String[] args:在Java早期使用的,用来在命令行窗口中接收命令行的参数的输入 14 15 // System.out.println(args); // [Ljava.lang.String;@15db9742 16 // System.out.println(args.length); // 0 17 18 // 使用javac对当前代码文件进行编译,再使用java Sample07 "字符串1" "字符串2" "字符串3",可以看到命令行窗口中显示出参数列表的值 19 for (String item : args) { 20 System.out.println(item); 21 } 22 } 23 }
1 package cn.temptation; 2 3 public class Sample08 { 4 public static void main(String[] args) { 5 // 大括号的玩法总结 6 // 代码块:Java中,使用大括号{}将语句包含其中,称为代码块 7 8 // 1、局部代码块(联想到局部变量) 9 // 位置:在方法内 10 // 作用:限定变量的作用范围 11 12 // 2、构造代码块(联想到构造函数) 13 // 位置:在类中,和成员变量、成员方法、构造函数同级的位置 14 // 作用:从构造代码块的执行效果看,因为它的执行在构造函数之前,所以可以考虑把构造函数及其重载方法中相同的语句提取出来放在构造代码块中 15 16 // 3、静态代码块(联想到静态成员) 17 // 位置:在类中,和成员变量、成员方法、构造函数、构造代码块同级的位置 18 // 作用:从静态代码块的执行效果看,静态代码块中的语句比构造代码块中的语句还要先执行,且只执行一次 19 // 常常用于先于构造代码块等执行且只执行一次语句的场合,比如:数据库连接 20 21 // 局部代码块 22 // { 23 // // 局部变量的声明和赋值在局部代码块内部 24 // int i = 2; 25 // System.out.println(i); 26 // } 27 // 局部代码块限定了其中的局部变量i的作用域,使得在局部代码块外的语句无法访问在局部代码块内声明的变量 28 // 语法错误:i cannot be resolved to a variable 29 // System.out.println(i); 30 31 // int j = 3; 32 // System.out.println(j); 33 // { 34 // // 修改局部变量赋值在局部代码块内部 35 // j = 4; 36 // System.out.println(j); 37 // } 38 // // 局部代码块外的语句可以访问在局部代码块外声明且在局部代码块内部修改赋值的变量 39 // System.out.println(j); 40 41 // 创建一个Test类类型的对象 42 Test test = new Test(); 43 44 // 再创建一个Test类类型的对象 45 Test testEx = new Test(); 46 } 47 48 // 静态代码块 49 static { 50 System.out.println("这是Sample08类中的静态代码块"); 51 } 52 53 // 注意:Sample08类中的静态代码块的显示先于Test类中的静态代码块的显示,这是因为类的加载先后顺序决定的(程序入口main主函数所在的类先被加载) 54 } 55 56 class Test { 57 // 成员变量 58 private int number; 59 60 // 构造函数(无参) 61 public Test() { 62 System.out.println("这是无参构造函数"); 63 // 因为不知道会执行哪一种构造函数的形式,所以每种构造函数中都要进行对成员变量的赋值操作 64 // this.number = 123; 65 } 66 67 // 构造函数(有参) 68 public Test(int number) { 69 System.out.println("这是有参构造函数"); 70 // 因为不知道会执行哪一种构造函数的形式,所以每种构造函数中都要进行对成员变量的赋值操作 71 // this.number = 123; 72 } 73 74 // 构造代码块 75 { 76 System.out.println("这是构造代码块"); 77 // 在构造代码块中编写构造函数及其重载方法中都有的语句,这样可以节省大量的重复代码 78 this.number = 123; 79 } 80 81 // 静态代码块 82 static { 83 System.out.println("这是静态代码块"); 84 } 85 86 // 成员方法 87 }
1 package cn.temptation; 2 3 public class Sample09 { 4 public static void main(String[] args) { 5 // Man man = new Man(); 6 // man.setName("吕布"); 7 // man.setAge(20); 8 // man.eat(); 9 // man.earn(); 10 // 11 // Woman woman = new Woman(); 12 // woman.setName("貂蝉"); 13 // woman.setAge(16); 14 // woman.eat(); 15 // woman.pay(); 16 17 // 发现问题:原先Man类 和 Woman类所特有的行为,在Person类上都不再是特有的了,这种Person类的设计扩大了行为能力 18 // Person person1 = new Person(); 19 // person1.setName("吕布"); 20 // person1.setAge(20); 21 // person1.eat(); 22 // person1.earn(); 23 // person1.pay(); 24 } 25 } 26 27 //// 男人类 28 //class Man { 29 // // 成员变量 30 // private String name; 31 // private int age; 32 // 33 // // 成员方法 34 // public String getName() { 35 // return name; 36 // } 37 // 38 // public void setName(String name) { 39 // this.name = name; 40 // } 41 // 42 // public int getAge() { 43 // return age; 44 // } 45 // 46 // public void setAge(int age) { 47 // this.age = age; 48 // } 49 // 50 // // 自定义成员方法 51 // public void eat() { 52 // System.out.println("吃饭"); 53 // } 54 // 55 // public void earn() { 56 // System.out.println("赚钱"); 57 // } 58 //} 59 // 60 //// 女人类 61 //class Woman { 62 // // 成员变量 63 // private String name; 64 // private int age; 65 // 66 // // 成员方法 67 // public String getName() { 68 // return name; 69 // } 70 // 71 // public void setName(String name) { 72 // this.name = name; 73 // } 74 // 75 // public int getAge() { 76 // return age; 77 // } 78 // 79 // public void setAge(int age) { 80 // this.age = age; 81 // } 82 // 83 // // 自定义成员方法 84 // public void eat() { 85 // System.out.println("吃饭"); 86 // } 87 // 88 // public void pay() { 89 // System.out.println("花钱"); 90 // } 91 //} 92 93 // 观察Man类 和 Woman类的代码中有太多相同的代码,所以我们考虑不使用两个类去表示,就用一个类表示,考虑男人类、女人类都是人类 94 //class Person { 95 // // 成员变量 96 // private String name; 97 // private int age; 98 // 99 // // 成员方法 100 // public String getName() { 101 // return name; 102 // } 103 // 104 // public void setName(String name) { 105 // this.name = name; 106 // } 107 // 108 // public int getAge() { 109 // return age; 110 // } 111 // 112 // public void setAge(int age) { 113 // this.age = age; 114 // } 115 // 116 // // 自定义成员方法 117 // public void eat() { 118 // System.out.println("吃饭"); 119 // } 120 // 121 // public void earn() { 122 // System.out.println("赚钱"); 123 // } 124 // 125 // public void pay() { 126 // System.out.println("花钱"); 127 // } 128 //}
1 package cn.temptation; 2 3 public class Sample10 { 4 public static void main(String[] args) { 5 // 想把若干个不同的类的相同的成员变量和成员方法提取出来做抽象,形成一个更高级别的抽象的类 6 // 但是它们的不同的成员变量和成员方法如何使用? 7 8 // Java中提供了 继承 的机制 9 10 // 面向对象的三大特点: 11 // 1、封装性:encapsulation 12 // 2、继承性:inheritance 13 // 3、多态性:polymorphism 14 15 // 继承的格式: 子类 extends 父类 16 17 // 1、将子类中相同的成员变量 和 成员方法都抽取出来放在父类中,减少子类中的代码 18 // 2、通过extends关键字,让子类使用父类中的这些相同的成员变量和成员方法,这样和把这些成员写在子类中效果相同 19 20 Man man = new Man(); 21 man.setName("吕布"); 22 man.setAge(20); 23 man.eat(); 24 man.earn(); 25 // 语法错误:The method pay() is undefined for the type Man 26 // man.pay(); 27 28 Woman woman = new Woman(); 29 woman.setName("貂蝉"); 30 woman.setAge(16); 31 woman.eat(); 32 woman.pay(); 33 // 语法错误:The method earn() is undefined for the type Woman 34 // woman.earn(); 35 36 // 子类从父类继承而来,自然把父类的成员变量 和 成员方法都一股脑儿拿来使用 37 38 // 【继承的优点】 39 // 1、减少了代码量 40 // 2、方便了修改 41 // 3、丰富了类和类之间的关系 42 43 // 【继承的缺点】 44 // 1、继承是无法选择(不论子类要还是不要,只要继承了,都给子类了) 45 // 2、类与类之间形成了较强的耦合度 46 47 // 【设计的原则:好的设计,追求的是"高内聚、低耦合"】 48 49 // 中国古代士大夫的自我准则:修身、齐家、平天下 50 // 做好面向对象的设计准则:同上 51 } 52 } 53 54 // 人类 55 class Person { 56 // 成员变量 57 private String name; 58 private int age; 59 60 // 成员方法 61 public String getName() { 62 return name; 63 } 64 65 public void setName(String name) { 66 this.name = name; 67 } 68 69 public int getAge() { 70 return age; 71 } 72 73 public void setAge(int age) { 74 this.age = age; 75 } 76 77 // 自定义的成员方法 78 public void eat() { 79 System.out.println("吃饭"); 80 } 81 } 82 83 // 男人类 84 class Man extends Person { 85 // 成员变量 86 87 // 成员方法 88 public void earn() { 89 System.out.println("赚钱"); 90 } 91 } 92 93 // 女人类 94 class Woman extends Person { 95 // 成员变量 96 97 // 成员方法 98 public void pay() { 99 System.out.println("花钱"); 100 } 101 }
1 package cn.temptation; 2 3 public class Sample11 { 4 public static void main(String[] args) { 5 // 继承的特点: 6 // Java中的继承是单继承,不是多继承(指的是类的继承),多继承在现实世界中是可以的,比如:小孩从父母双方继承基因 7 8 // 理解单继承: 9 // 1、被继承的类是单个的 10 // 2、继承并不只有一层,可以是多层的(也就是继承链),但是继承链上的每一层都是单继承 11 } 12 } 13 14 //class GrandFather { 15 // 16 //} 17 // 18 //class Father extends GrandFather { 19 // 20 //} 21 // 22 //class Mother { 23 // 24 //} 25 // 26 //class Baby extends Father { // 语法OK 27 ////class Baby extends Mother { // 语法OK 28 ////class Baby extends Father, Mother { // 语法出错 29 ////class Baby extends Father + Mother { // 语法出错 30 ////class Baby extends Father Mother { // 语法出错 31 // 32 //}
1 package cn.temptation; 2 3 public class Sample12 { 4 public static void main(String[] args) { 5 // 继承是可以传递的 6 // 只要在继承链上,链的下级可以得到上级及上级的上级的...成员变量 和 成员方法(对上级的查找是一直向上直到继承链的源头) 7 8 // 通过继承链得到成员的缺点:当前类的对象使用成员时,不知道自身的成员变量或成员方法到底来自于哪一个上级 9 // IDE对这个缺点进行了一些补救,使用成员变量或成员方法时,会在成员后标明是哪个上级 10 Baby baby = new Baby(); 11 baby.showByBaby(); 12 baby.showByFather(); 13 baby.showByGrandFather(); 14 } 15 } 16 17 class GrandFather { 18 public void showByGrandFather() { 19 System.out.println("这是GrandFather的成员方法"); 20 } 21 } 22 23 class Father extends GrandFather { 24 public void showByFather() { 25 System.out.println("这是Father的成员方法"); 26 } 27 } 28 29 class Baby extends Father { 30 public void showByBaby() { 31 System.out.println("这是Baby的成员方法"); 32 } 33 }