文章目录
- 60 面向对象和面向过程
- 61 对象和数据管理
- 62 对象和类的概念
- 63 一个典型类的写法和调用_类的UML图入门
- 64 面向对象的内存分析*
- 65 构造方法详解_构造方法重载
- 66 垃圾回收机制介绍_垃圾回收算法
- 67 通用分代垃圾回收机制
- 68 对象创建过程和this的本质
- 69 static关键字_内存分析静态变量和静态方法
- 70 静态初始化块_继承树的追溯
- 71 JAVA的 参数传值机制_值传递
- 72 Java包机制_package的使用_jdk提供的常见包的作用
- 73 import详解_静态导入详解
- 74 继承_instanceOf的使用
- 75 方法的重写override_返回值类型问题
- 76 Object类的用法_重写toString方法
- 77 equals方法的重写_阅读Object和toString源码
- 78 super父类对象引用_继承树追溯问题
- 79 封装的使用_访问控制符
- 80 封装的使用细节_javabean的规则
- 81 多态_多态的三个必要条件
- 82 对象的转型_ClassCastException处理
- 83 final修饰变量、方法和类
- 84 数组的使用
- 85 数组的初始化
- 86 数组的遍历_for each循环
官方笔记入口:http://www.sxt.cn/Java_jQuery_in_action/History_Direction.html
60 面向对象和面向过程
面向过程指按步骤实现,适用于简单任务,比如如何开车,比如如何把大象装冰箱,适合简单、不需要协作的事务,按步骤即可实现。
面向对象,应用于复杂任务,需要协作完成,比如如何造一辆车,先造每个部分,再组装。
总结:
- 都是解决问题的思维方式,都是代码组织的方式。
- 解决简单问题使用面向过程
- 解决复杂问题:宏观上使用面向对象把握,微观上仍然是面向过程。
61 对象和数据管理
对象可以理解为在内存中的一个内存块,包含一个数据集。
科学、企业管理、 程序开发都遵循一个原则:量变引起质变。
企业大了,就需要变更管理方式;程序中数据多了,就需要变更对程序的管理方式。
分为三个阶段:
1.数据无管理时代:数据少,基本不需要刻意管理。企业创业阶段,人数少,也无需管理。
2.数组管理和企业部门制:同类型数据类型增多,如存储一个班每个人的年龄,采用数组来进行管理。企业人数多了,分成不同部门,每个部门类似一个数组,负责执行某种职能。
3.对象和企业项目制
企业继续发展,一个项目可能需要多个部门协同来完成,如果继续采用部门制来完成,管理会混乱。以项目为单位进行管理是更好的方式,一个完整的项目组,类似一个小型创业公司,各个部门都有,包括行政后勤人员、财务核算人员、开发、售前、售后、测试人员、设计人员等。大型公司往往采用这种项目制的方式进行管理。
同理,编程开发继续发展,各种类型的变量增多,数组管理已经难以满足要求。方法(对数据操作的管理)也变得复杂。于是面向对象来开发。
为了便于协作和管理,我们“将相关数据和相关方法封装到一个独立的实体”,于是对象产生了。
比如将一个学生作为一个对象
包括:属性(静态特征):年龄:18,姓名:李四,学号:123
方法(动态行为):学习,吃饭,考试
62 对象和类的概念
比如给我们很多天使的图片,我们根据图片抽象出天使的特征,归纳出一个天使类:带翅膀;女孩;善良;头上有光环。通过这个过程,得到了类,即类就是对象的抽象。
类可以看做是一个模板,或者图纸,系统根据类的定义来造出对象。比如造汽车,类就是图纸,里面规定了汽车的详细参数信息,我们根据图纸造出一辆汽车,得到汽车这个对象。
类叫做class;对象叫做Object,instance(实例)。某个类的对象就是某各类的实例。
·
类包括属性和方法。
属性(filed或成员变量) 用于定义该类或该类对象包含的数据或者说静态特征,作用范围是整个类体。定义成员变量要对其初始化,否则系统初始为默认值。
方法用于定义该类或该类实例的行为特征和功能实现。方法是类和对象行为特征的抽象,类似于面向过程中的函数。 面向过程中,函数是最基本单位,整个程序是由一个个函数调用组成的。面向对象中,整个程序的基本单位是类,方法是从属于类和对象的。
//定义一个学生类 认识类
public class Student {
//定义属性
int id;
String name;
int age;
//只有属性没有方法,在C语言中叫结构体。
//方法
void study() {
System.out.println("我在认真学习!");
}
void play() {
System.out.println("我在玩游戏!王者荣耀!");
}
//构造方法。 用于创建这个类的对象。无参的构造方法可以由系统自动创建。
Student(){
}
//上面是无参的构造方法,可以省略不写
//调用 程序执行的入口,必须要有main方法。
public static void main(String[] args) {
Student stu = new Student(); //在Student类下new一个对象命名为stu
stu.play(); //对象的方法调用
}
}
63 一个典型类的写法和调用_类的UML图入门
//定义一个学生类 认识类
public class Student {
//定义属性
int id;
String name;
int age;
Computer comp; //引用自别的类 ,表示每个学生都有对应的电脑类。属性可以是一个别的类的对象。
//只有属性没有方法,在C语言中叫结构体。
//方法
void study() {
System.out.println("我在认真学习!编程用的电脑品牌是" + comp.brand + "。");
}
void play() {
System.out.println("我在玩游戏!王者荣耀!");
}
//构造方法。 用于创建这个类的对象。无参的构造方法可以由系统自动创建。
Student(){
}
//上面是无参的构造方法,可以省略不写
//调用 程序执行的入口,必须要有main方法。
public static void main(String[] args) {
Student stu = new Student(); //在Student类下new一个对象命名为stu
stu.id = 1001;
stu.name = "李四";
stu.age =18;
Computer c1 = new Computer();
c1.brand = "ASUS华硕A550j";
//上面建好了一个电脑类的对象,并赋予了初值
//把这个对象给Student的comp属性
stu.comp = c1;
stu.study();
stu.play(); //对象的方法调用
}
}
//创建一个新的类 Computer 模拟学生使用某品牌电脑学习
class Computer{
String brand; //品牌
} //上面是一个新建的类,类和类之间也可以引用
类的互相引用容易造成混乱,因此采用UML图来理清头绪。UML图包括类名、属性、方法。可以用对应的工具软件来绘制。上面程序UML图如下:
64 面向对象的内存分析*
Java虚拟机的内存可以分为三个区域:栈stake、堆heap、方法区method area
- 为每个线程创建一个帧栈,每个栈包含多个方法,每个方法由一个元素表示,一个元素是一个栈帧,存储局部变量、操作数、方法出口等。先进后出。
//定义一个学生类 认识类
public class SxtStu {
//定义属性
int id;
String name;
int age;
Computer comp; //引用自别的类 ,表示每个学生都有对应的电脑类。属性可以是一个别的类的对象。
//只有属性没有方法,在C语言中叫结构体。
//方法
void study() {
System.out.println("我在认真学习!使用电脑:" + comp.brand );
}
void play() {
System.out.println("我在玩游戏!王者荣耀!");
}
//构造方法。 用于创建这个类的对象。无参的构造方法可以由系统自动创建。
SxtStu(){
}
//上面是无参的构造方法,可以省略不写
//用命令行加载类的命令: javac Student.java ,java Student 开始启动虚拟机,加载数据到方法区
//调用 程序执行的入口,必须要有main方法。
public static void main(String[] args) {
SxtStu stu = new SxtStu(); //在Student类下new一个对象命名为stu
stu.id = 1001;
stu.name = "高淇";
stu.age =18;
Computer c1 = new Computer();
c1.brand = "联想";
//上面建好了一个电脑类的对象,并赋予了初值
//把这个对象给Student的comp属性
stu.comp = c1;
stu.study();
stu.play(); //对象的方法调用
}
}
//创建一个新的类 Computer 模拟学生使用某品牌电脑学习
class Computer{
String brand; //品牌
} //上面是一个新建的类,类和类之间也可以引用
上面程序关于堆、栈、方法区的内存分配见下图:
65 构造方法详解_构造方法重载
构造器也叫构造方法(constructor),用于对象的初始化。
class Point{
double x,y;
//构造方法名称必须和类名保持一致
public Point(double _x,double _y) {
x = _x;
y = _y;
}
public double getDistance(Point p) { //求距离
return Math.sqrt((x - p.x)*(x - p.x) + (y - p.y) * (y - p.y));
}
}
public class TestConstructor {
public static void main(String[] args) {
Point p = new Point(3.0,4.0);
Point origin = new Point(0.0,0.0);
System.out.println(p.getDistance(origin));
}
}
构造方法重载:
public class User {
int id; // id
String name; // 账户名
String pwd; // 密码
public User() {
}
public User(int id, String name) {
// super(); //构造方法的第一句总是super(),不写系统也会默认加上
this.id = id; //this表示创建好的对象。
this.name = name;
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
// System.gc();
}
public static void main(String[] args) {
User u1 = new User();
User u2 = new User(101, "高小七");
User u3 = new User(100, "高淇", "123456");
}
}
66 垃圾回收机制介绍_垃圾回收算法
Java 引入了垃圾回收机制(Garbage Collection),令C++程序员最头疼的内存管理问题迎刃而解。Java程序员可以将更多的精力放到业务逻辑上而不是内存管理工作上,大大的提高了开发效率。
Java的内存管理很大程度指的就是对象的管理,其中包括对象空间的分配和释放。
对象空间的分配:使用new关键字创建对象即可。
对象空间的释放:将对象赋值null即可。
垃圾回收器将负责回收所有“不可达”对象的内存空间。
任何一种垃圾回收算法一般要做两件基本事情:
1.发现无用的对象
2.回收无用对象占用的内存空间
无用的对象就是指没有任何变量引用该对象。Java的垃圾回收器通过相关算法发现无用对象,并进行清除和整理。
垃圾回收相关算法:
1.引用计数法
2.引用可达法(根搜索算法)
67 通用分代垃圾回收机制
分代垃圾回收基于这样的事实:不同的对象生命周期是不一样的。因此不同生命周期的对象可以采取 不同的回收算法,以便提高回收效率。将对象分为年轻代、年老代、持久代。JVM将堆内存(放对象的地方)划分为Eden(放置年轻代对象)、Survivor和Tenured/Old空间区。
68 对象创建过程和this的本质
public class TestThis {
int a, b, c; //属性
TestThis(int a, int b) { //类的对象
this.a = a;
this.b = b;
}
TestThis(int a, int b, int c) { //类的对象
this(a,b);
this.c = c;
}
void sing() { //方法
}
void eat() { //方法
this.sing(); // 调用本类中的sing(); 这里this可以省略,不会造成歧义
System.out.println("你妈妈喊你回家吃饭!");
}
//this不能用于static方法中
public static void main(String[] args) { //调用
TestThis hi = new TestThis(2, 3);
hi.eat();
}
}
69 static关键字_内存分析静态变量和静态方法
在类中,用static生命的成员变量为静态成员变量,也称为类变量。类变量的生命周期和类相同,在整个应用程序直行期间都有效。
static修饰的成员变量和方法,从属于类。普通变量和方法从属于对象。
/**
* 测试static关键字的用法
* @author 高淇
*
*/
public class User2 {
int id; // id
String name; // 账户名
String pwd; // 密码
static String company = "北京尚学堂"; // 公司名称
public User2(int id, String name) {
this.id = id;
this.name = name;
}
public void login() {
printCompany();
System.out.println(company);
System.out.println("登录:" + name);
}
public static void printCompany() { //静态方法 从属于类
// login();//调用非静态成员,编译就会报错 ,编译就会报错 可以看内存分析图
System.out.println(company);
}
public static void main(String[] args) {
User2 u = new User2(101, "高小七");
User2.printCompany();
User2.company = "北京阿里爷爷";
User2.printCompany();
}
}
方法区里面装的是类的信息,包括类的代码,静态变量,静态方法,常量(一般只包括字符串)。相当于图纸或模板。
堆里面装的是一个个对象的信息,包括一般变量和一般方法(非静态方法)。
静态方法中不能调用非静态成员。非静态方法中可以调用静态变量或静态方法。
如下图:
70 静态初始化块_继承树的追溯
上面的注意事项讲到继承再回头看。
/**
* 测试静态初始化块的使用
* @author 高淇
*
*/
public class User3 {
int id; //id
String name; //账户名
String pwd; //密码
static String company; //公司名称
//静态初始化块,用于类的初始化操作。在静态初始化块中不能直接访问非static成员
static { //静态块 注意这里不是方法,仅仅是个语句块,用static修饰了
System.out.println("执行类的初始化工作");
company = "北京尚学堂"; //只能访问静态成员
printCompany();//执行对象
} //这里是对类的初始化,还没有对象,因此是不能访问普通变量的
//方法
public static void printCompany(){ //静态方法,用于上面静态块进行调用
System.out.println(company); //打印
}
public static void main(String[] args) { //main方法,这里什么都没做,并没有调用对象
User3 u3 = null;
}
}
/*
* 最后结果:执行类的初始化工作
* 北京尚学堂
* 这个结果并不是main方法调用得到的,而是执行静态初始化块对类进行初始化得到的。
* 上述代码中静态初始化块进行了打印和执行后面建立的静态方法printCompany(),
*/
71 JAVA的 参数传值机制_值传递
/**
* 测试参数传值机制
* @author 高淇
*
*/
public class User4 {
int id; //id
String name; //账户名
String pwd; //密码
public User4(int id, String name) {
this.id = id;
this.name = name;
}
public void testParameterTransfer01(User4 u){
u.name="高小八";
}
public void testParameterTransfer02(User4 u){
u = new User4(200,"高三");
}
public static void main(String[] args) {
User4 u1 = new User4(100, "高小七");
u1.testParameterTransfer01(u1);
System.out.println(u1.name); //结果是高小八,传递的u1是指针型(引用型)
u1.testParameterTransfer02(u1);
System.out.println(u1.name); //结果仍然是高小八
}
}
72 Java包机制_package的使用_jdk提供的常见包的作用
包机制是Java中管理类的重要手段。开发中,我们会遇到大量同名的类,通过包我们很容易解决类同名的问题,也可以实现对类的有效管理。包对于类,相当于文件夹对文件的作用。
以后写类一定要先写包名,且包名在类代码中是非注释语句中的第一句。
package cn.sxt.oo; //一定是非注释性语句的第一句
public class User {
public static void main(String[] args) {
String str;
}
}
查看包的属性:右键-选择properties-resorce-location(查看所在工作空间)
java.lang中所有的类不用导入可以直接使用,如string,system都是其中的类。
73 import详解_静态导入详解
import主要用于调用其他包的类,如果没有import导入其他包的类,默认调用本包的类。
注:按Ctrl+点击某个类名可以查看源代码。
注:如果精确导入一个包下面的类,同时也导入一个包下面所有的类,引用的时候引用的是精确导入的那个类。精确导入的类优先级是最高的,未导入的本包的类是最低的。
遇到多个同名类不好分辨,引用时直接写出导入路径:包名+类名
package cn.sxt.oo;
//import cn.sxt.oo2.Human; //调用其他包的类要通过import
public class TestEncapsulation2 {
public static void main(String[] args) {
cn.sxt.oo2.Human h = new cn.sxt.oo2.Human(); //Human类本类是默认的,出了包不能用
//然后新建了个公开类Human,就可以在整个项目引用了
// h.age = 13;
// h.name = "高淇"; //name为default属性,不能被不同包的类访问
h.sayAge(); //访问其他包的公开方法
}
}
class Girl extends cn.sxt.oo2.Human {
//girl是human的子类,继承之后可以继承其protected属性,即使不在一个包也可以
void sayGood(){
System.out.println(height);
}
}
74 继承_instanceOf的使用
本章重点针对面向对象的三大特征:继承、封装、多态进行详细的讲解。另外还包括抽象类、接口、内部类等概念。
注意:本章主要是进行语法性质的了解,不要期望直接学习就搞透面向对象。本章只是起点,之后学的都是面向对象的应用。
继承让我们更加容易实现类的扩展。 比如,我们定义了人类,再定义Boy类就只需要扩展人类即可。实现了代码的重用,不用再重新发明轮子(don’t reinvent wheels)。
从英文字面意思理解,extends的意思是“扩展”。子类是父类的扩展。现实世界中的继承无处不在。比如:
图5-1 现实世界中的继承.png
上图中,哺乳动物继承了动物。意味着,动物的特性,哺乳动物都有;在我们编程中,如果新定义一个Student类,发现已经有Person类包含了我们需要的属性和方法,那么Student类只需要继承Person类即可拥有Person类的属性和方法。
选中类,单击右键,选中Open type hierarchy,则能看到此类的继承关系。
或者指向类之后,按Ctrl+t,也能直接看到此类的继承关系。
1.父类也称作超类、基类、派生类等。
2.Java中只有单继承,没有像C++那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难于维护。
3.Java中类没有多继承,接口有多继承。
4.子类继承父类,可以得到父类的全部属性和方法 (除了父类的构造方法),但不见得可以直接访问(比如,父类私有的属性和方法)。
5.如果定义一个类时,没有调用extends,则它的父类是:java.lang.Object。
instanceof是二元运算符,左边是对象,右边是类;当对象是右面类或子类所创建对象时,返回true;否则,返回false。即检验左边是不是右边类的对象。或是不是右边类的子类的对象。
Student stu2 = new Student("希希",6,"挖掘机专业");//利用构造方法新建对象并初始化
System.out.println(stu2 instanceof Student);
System.out.println(stu2 instanceof Person );
System.out.println(stu2 instanceof Object );
//结果都是true
75 方法的重写override_返回值类型问题
指的是子类通过重写父类的方法,可以用自身的行为替换父类的行为。方法的重写是实现多态的必要条件。重写也称为覆盖。
方法的重写需要符合下面的三个要点:
1.“==”: 方法名、形参列表相同。
2.“≤”:返回值类型和声明异常类型,子类小于等于父类。
3.“≥”: 访问权限,子类大于等于父类。(见封装那节)
package cn.sxt.oo2;
public class TestOverride {
public static void main(String[] args) {
Horse h = new Horse();
h.run();
}
}
class Vehicle { //交通工具
public void run(){
System.out.println("跑....");
}
public void stop(){
System.out.println("停止!");
}
public Person whoIsPsg(){
return new Person();
}
}
class Horse extends Vehicle {
public void run(){
System.out.println("四蹄翻飞,嘚嘚的。。。");
}
public Student whoIsPsg(){//返回值类型小于等于父类的类型
return new Student();
}
}
76 Object类的用法_重写toString方法
package cn.sxt.oo2;
public class TestObject {
public static void main(String[] args) {
// Object obj;
TestObject to = new TestObject();
System.out.println(to);//System.out.println(to.toString)
Person2 p2 = new Person2("希希", 6);
System.out.println(p2.toString());
}
//toString的重写
public String toString(){
return "测试Object对象";
}
}
class Person2 {
String name;
int age;
@Override
public String toString() {
return name+",年龄:"+age;
}
public Person2(String name, int age) {
this.name = name;
this.age = age;
}
}
77 equals方法的重写_阅读Object和toString源码
“==”代表比较双方是否相同。如果是基本类型则表示值相等,如果是引用类型则表示地址相等即是同一个对象。
Object类中定义有:public boolean equals(Object obj)方法,提供定义“对象内容相等”的逻辑。比如,我们在公安系统中认为id相同的人就是同一个人、学籍系统中认为学号相同的人就是同一个人。
Object 的 equals 方法默认就是比较两个对象的hashcode,是同一个对象的引用时返回 true 否则返回 false。但是,我们可以根据我们自己的要求重写equals方法。
JDK提供的一些类,如String、Date、包装类等,重写了Object的equals方法,调用这些类的equals方法, x.equals (y) ,当x和y所引用的对象是同一类对象且属性内容相等时(并不一定是相同对象),返回 true 否则返回 false。
78 super父类对象引用_继承树追溯问题
super是直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性。
使用super调用普通方法,语句没有位置限制,可以在子类中随便调用。
若是构造方法的第一行代码没有显式的调用super(…)或者this(…);那么Java默认都会调用super(),含义是调用父类的无参数构造方法。这里的super()可以省略。
package cn.sxt.oo2;
public class TestSuper01 {
public static void main(String[] args) {
new ChildClass().f(); //调用子类的f方法
}
}
class FatherClass {
public int value;
public void f(){
value = 100;
System.out.println ("FatherClass.value="+value);
}
}
class ChildClass extends FatherClass {
public int value;
public void f() { //重新父类的方法
super.f(); //调用父类对象的普通方法
value = 200;
System.out.println("ChildClass.value="+value);
System.out.println(value);
System.out.println(super.value); //调用父类对象的成员变量
}
}
构造方法调用顺序:
构造方法第一句总是,默认:super(…)来调用父类对应的构造方法。所以,流程就是:先向上追溯到Object,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止。这就是继承树追溯。
注:静态初始化块调用顺序,与构造方法调用顺序一样,不再重复。见本文70小节
package cn.sxt.oo2;
public class TestSuper02 {
public static void main(String[] args) {
System.out.println("开始创建一个ChildClass对象......");
new ChildClass2(); //新建对象,相当于调用这个类
}
}
class FatherClass2 {
public FatherClass2() {
super();这行是默认的,不写的话系统也会默认执行这一句,这里追溯到object类
System.out.println("创建FatherClass");
}
}
class ChildClass2 extends FatherClass2 {
public ChildClass2() {
super(); //这行是默认的,不写的话系统也会默认执行这一句,这里追溯到father类
System.out.println("创建ChildClass");
}
}
·属性/方法查找顺序也是按照追溯来进行:(比如:查找变量h)
1. 查找当前类中有没有属性h
2. 依次上溯每个父类,查看每个父类中是否有h,直到Object
3. 如果没找到,则出现编译错误。
4. 上面步骤,只要找到h变量,则这个过程终止。
79 封装的使用_访问控制符
我要看电视,只需要按一下开关和换台就可以了。有必要了解电视机内部的结构吗?有必要碰碰显像管吗?制造厂家为了方便我们使用电视,把复杂的内部细节全部封装起来,只给我们暴露简单的接口,比如:电源开关。具体内部是怎么实现的,我们不需要操心。
需要让用户知道的才暴露出来,不需要让用户知道的全部隐藏起来,这就是封装。说的专业一点,封装就是把对象的属性和操作结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。
我们程序设计要追求**“高内聚,低耦合**”。 高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合是仅暴露少量的方法给外部使用,尽量方便外部调用。
编程中封装的具体优点:
1. 提高代码的安全性。
2. 提高代码的复用性。
3. “高内聚”:封装细节,便于修改内部代码,提高可维护性。
4. “低耦合”:简化外部调用,便于调用者使用,便于扩展和协作。
Java是使用“访问控制符”来控制哪些细节需要封装,哪些细节需要暴露的。 Java中4种“访问控制符”分别为private、default、protected、public,它们说明了面向对象的封装性,所以我们要利用它们尽可能的让访问权限降到最低,从而提高安全性。
下面详细讲述它们的访问权限问题。其访问权限范围如表5-1所示
1. private 表示私有,只有自己类能访问
2. default表示没有修饰符修饰,只有同一个包的类能访问
3. protected表示可以被同一个包的类以及其他包中的子类访问
4. public表示可以被该项目的所有包中的所有类访问
子类:扩展引用过这个类的类
利用上述不同权限的访问控制符来对类或属性、方法进行封装,相当于造电视机时加上外壳,使其变得不透明,保证了使用的安全性。
利用下面分别属于俩包的三组代码来理解
package cn.sxt.oo2;
public class Human {
private int age = 2;
String name; //可以被本包下面的类访问
protected int height ;
public void sayAge(){
System.out.println(age);
}
}
package cn.sxt.oo2;
/**
* 测试封装
* @author 高淇
*
*/
public class TestEncapsulation{
public static void main(String[] args) {
Human h = new Human();
//h.age = 13;
h.name = "高琪"; //本包其他默认属性
h.height = 230; //protected属性 同一个包中可访问
}
}
class Boy extends Human{
void sayHello(){
//System.out.println(age);
//子类无法使用父类的私有属性和方法
}
}
package cn.sxt.oo;
import cn.sxt.oo2.Human;
public class TestEncapsulation2 {
public static void main(String[] args) {
Human h = new Human(); //Human类本类是默认的,出了包不能用
//然后新建了个公开类Human,就可以在整个项目引用了
// h.age = 13;
// h.name = "高淇"; //name为default属性,不能被不同包的类访问
h.sayAge(); //访问其他包的公开方法
}
}
class Girl extends Human {
//girl是human的子类,继承之后可以继承其protected属性,即使不在一个包也可以
void sayGood(){
System.out.println(height);
}
}
80 封装的使用细节_javabean的规则
类的属性的处理:
1. 一般使用private访问权限。私有就完事儿了,安全。
外部向更改的话,调用那个类下面设置的公开的setName方法。即通过公开的方法来对私有属性改动。返回那个熟属性,用getName方法
2. 提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操作(注意:boolean变量的get方法是is开头!)。
3. 一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰(一般只把特别不希望别的类访问的方法设为private,其他大部分用public即可,即让项目下所有类均可访问)
将属性私有之后将控制权暴露于方法,可以利用方法对属性的特性加以灵活控制。
set/get方法的自动生成:右键-source-generate getters and setters
package cn.sxt.oo2;
/**
* 仍然测试封装
* @author 高淇
*
*/
public class Person4 {
private int id; //一般类的属性设置为私有
private String name;
private int age;
private boolean man;
public void setName(String name){
//通过公开的方法来对私有属性改动
this.name = name;
}
public String getName(){ //返回这个类的name属性
return this.name;
}
public void setAge(int age) {
if(age>=1&&age<=130){ //利用if对属性值的更改加以限制
this.age = age;
}else{
System.out.println("请输入正常的年龄!");
}
}
public int getAge(){
return this.age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public boolean isMan() {
return man;
}
public void setMan(boolean man) {
this.man = man;
}
//快捷操作 右键-source-generate getters and setters
}
81 多态_多态的三个必要条件
多态指的是同一个方法调用,由于对象不同可能会有不同的行为。现实生活中,同一个方法,具体实现会完全不同。 比如:同样是调用人的“休息”方法,张三是睡觉,李四是旅游,高淇老师是敲代码,数学教授是做数学题; 同样是调用人“吃饭”的方法,中国人用筷子吃饭,英国人用刀叉吃饭,印度人用手吃饭。
多态的要点:
1. 多态是方法的多态,不是属性的多态(多态与属性无关)。
2. 多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类对象。
3. 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。
package cn.sxt.oo2;
/**
* 测试多态
* @author 高淇
*
*/
public class TestPolym {
public static void main(String[] args) {
Animal a = new Animal();
animalCry(a);
Animal d = new Dog(); //自动向上转型
animalCry(d);
Animal c = new Cat();
animalCry(new Cat());
Dog d2 = (Dog) d; //强制向下转型
d2.seeDoor();
// Dog d3 = (Dog) c;
// d3.seeDoor();
}
static void animalCry(Animal a){ //静态方法
a.shout();
}
/*static void animalCry(Dog a){
a.shout();
}
static void animalCry(Cat a){
a.shout();
}*/
}
class Animal {
public void shout() {
System.out.println("叫了一声!");
}
}
class Dog extends Animal { //条件:1:继承
public void shout() { //条件2:方法重写
System.out.println("旺旺旺!");
}
public void seeDoor(){
System.out.println("看门!!!");
}
}
class Cat extends Animal {
public void shout() {
System.out.println("喵喵喵喵!");
}
}
82 对象的转型_ClassCastException处理
对象转型原则:向上自动转型、向下强制转型。
ClassCastException:类型转化异常,属于常见异常的一种。
Animal d = new Dog(); //自动向上转型
animalCry(d);
Animal c = new Cat();
animalCry(new Cat());
Dog d2 = (Dog) d; //强制向下转型
d2.seeDoor();
Dog d3 = (Dog) c;
//未报错,但这里c本质上还是个Cat,系统默认为animal进行了强制转型
d3.seeDoor();
//依然未报错,但不能正确执行
上面这种情况编译正确但运行错误,是异常的一种:ClassCastException。如下图:
知道了这种异常的原因,就要注意避免这种异常。
83 final修饰变量、方法和类
84 数组的使用
数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。数组的三个基本特点:
1. 长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
2. 其元素必须是相同类型,不允许出现混合类型。
3. 数组类型可以是任何数据类型,包括基本类型和引用类型。
数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中存储的。
注意事项
1. 声明的时候并没有实例化任何对象,只有在实例化数组对象时,JVM才分配空间,这时才与长度有关。
2. 声明一个数组的时候并没有数组真正被创建。
3. 构造一个数组,必须指定长度。
package cn.sxt.arrays;
public class Test01 {
public static void main(String[] args) {
int[] arr01 = new int[10] ; //索引下标[0, length-1]:0,1,2,3,4,5,6,7,8,9
String arr02[] = new String[5];
arr01[0] = 13;
arr01[1] = 15;
arr01[2] = 20;
// arr01[10] = 100; // java.lang.ArrayIndexOutOfBoundsException
//通过循环初始化数组
for(int i=0;i<arr01.length;i++){
arr01[i] = 10*i;
}
//通过循环读取数组里面元素的值
for(int i=0;i<arr01.length;i++){
System.out.println(arr01[i]);
}
User[] arr03 = new User[3];
arr03[0] = new User(1001,"高淇"); //对象数组里面存的是引用类型,即每个对象的地址,而非直接存储对象
arr03[1] = new User(1002,"高二淇");
arr03[2] = new User(1003,"高三淇");
for(int i=0;i<arr03.length;i++){
System.out.println(arr03[i].getName());
}
}
class User {
private int id;
private String name;
public User(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
85 数组的初始化
数组的初始化方式总共有三种:静态初始化、动态初始化、默认初始化。
86 数组的遍历_for each循环
for each是用来循环读取数组元素值的一种用法。