封装
是指隐藏事物的属性和实现细节。仅对外提供公共的访问方式。
好处:1.提高安全性;2.将变化隔离;
3.便于使用;
4.提供重用性;
封装原则:
1.将不需要对外提供内容都隐藏起来;
2.把属性都隐藏起来,提供公共的方法对其进行访问。
封装的步骤:
1.修改属性的可见性:设为private,防止错误数据的修改。
2.创建公有的set、get方法,用于属性的读写。
3.在set、get方法中加入属性控制语句,对属性的合法性进行判断。
案例:用封装的思想创建宠物
思路:分析需求
1.需要哪些类:狗类、企鹅类
2.狗类和企鹅类的属性:姓名、性别、健康度和亲密度
3.方法(行为):输出宠物的信息
创建狗类:
public class Dog {
private String name;
private String sex;
private int health;
private int love;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
if(health>0 && health<100) {
this.health = health;
}else {
System.out.println("健康值应该在0-100之间,默认值为60");
this.health=60;
}
}
public int getLove() {
return love;
}
public void setLove(int love) {
this.love = love;
}
public void speak() {
System.out.println("我的姓名是"+this.getName()+",健康值是"+this.getHealth()+",和主人的亲密程度是"+this.getLove()+",我的性别是"+this.getSex());
}
}
创建企鹅类:
public class penguin{
private String name;
private String sex;
private int health;
private int love;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
if(health>0 && health<100) {
this.health = health;
}else {
System.out.println("健康值应该在0-100之间,默认值为60");
this.health=60;
}
}
public int getLove() {
return love;
}
}
主程序:
import java.util.Scanner;
public class TestPet {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("欢迎来到宠物店!");
System.out.println("请输入要领养宠物的名称:");
Scanner s=new Scanner(System.in);
String name=s.next();
System.out.println("请选择要领养宠物的类型(1、狗狗 2、企鹅):");
int type=s.nextInt();
switch(type) {
case 1: //省略选择狗
System.out.println("请选择狗的性别(1、犬子 2、犬姐):");
int sexId_dog=s.nextInt();
String sexName_dog="";
if(sexId_dog==1) {
sexName_dog="犬子";
}
if(sexId_dog==2) {
sexName_dog="犬姐";
}
System.out.println("请选择狗的健康值(1-100之间):");
int health_dog=s.nextInt();
Dog d = new Dog();
d.setName(name);
d.setSex(sexName_dog);
d.setHealth(health_dog);
d.speak();
break;
case 2:
System.out.println("请选择企鹅的性别(1、Q仔 2、Q妹):");
int sexId1=s.nextInt();
String sexName_penguin="";
if(sexId1==1) {
sexName_penguin="Q仔";
}
if(sexId1==2) {
sexName_penguin="Q妹";
}
System.out.println("请选择企鹅的健康值(1-100之间):");
int health_penguin=s.nextInt();
penguin p = new penguin();
p.setName(name);
p.setSex(sexName_penguin);
p.setHealth(health_penguin);
p.speak();
}
}
}
结果:
心得体会:
Set方法是赋值
Get方法是取出
Private:私有
是一个权限修饰符。
用于修饰成员(成员变量和成员方法)。
被私有化的成员只在本类中有效。
常用之一:
将成员变量私有化,对外提供get、set方法。
方法对其进行访问,提高数据访问的安全性。
构造方法:
名称和类名相同,是创建对象是调用的方法。
* 作用:对对象进行初始化。* 常见对象的时候必须经过构造函数来进行初始化。
*
* 一个类中没有定构造方法,那么该类中就会有一个默认的空参数的构造方法。
* 如果一个类中定义了构造函数,那么类中的默认的构造函数就没有了。
*
* 一般函数和构造函数有什么区别?
* 构造函数:当对象创建时,就会调用与之对应的构造函数,并对对象进行初始化;
* 对象创建时,只调用一次。
* 一般函数:当对象被创建后需要函数功能时才被调用;
* 对象创建后,可调用多次。
*
* 什么时候要定义构造函数?
* 在描述事物时,该事物一存在,就具备一些内容,这些内容都定义在构造函数中。
* 构造函数可以有多个,用于对不同的对象进行针对性的初始化。
* 多个构造函数在类中是以重载的形式来体现的。
* 细节:
* 1.一般函数不能调用构造函数;
* 2.构造函数如果前面加了void就变成了一般函数;
* 3.构造函数中是有return语句的。
* 4.构造函数如果完成set功能,set方法还是需要的。
this关键字
* 当成员比变量和局部变量重名时,可以用this关键字来区分。
* this代表对象。代表哪个对象?当前对象。
* 什么叫做当前对象?this就是所在方法所属对象的引用。
* 简单地说,哪个对象调用了this所在的方法,this就代表哪个对象。
*
* this只能在方法内部使用,表示调用方法的那个对象的引用。
*
* 在方法内部调用同一个类中的另一个方法是就不用this关键字了,直接调用就好了。
* 当前方法中的this会自动应用到同一类中的其他方法。
*
* 当要返回当前方法的引用时通常这样写:return this
* 在构造器中调用构造器用this(),它只能定义在构造函数的第一行,因为初始化动作要先执行。
*
* 只有构造函数才能引用别的构造函数;而且一个构造函数只能引用一个构造函数
构造代码块:
可以给所有对象进行初始化。
static关键字
/**1.static是一个修饰符,修饰成员变量和成员函数,它被对象共享。
*2.共享数据出现在对象之前,没有对象时它可以被类名直接调用。
*
*static的特点:
*1.它是一修饰符,用来修饰成员;
*2.修饰的成员被所有对象所共享;
*3.static优先于对象而存在,因为static的成员随着类的加载而加载,随着类的消失而消失;
*4.static所修饰的成员多了一种调用方法,可以直接被类名调用。格式:类名.静态成员变量
*5.static修饰的是共享数据。对象中存储的是特有数据。
*
*成员变量和静态变量的区别:
*1.两个变量的生命周期不同。
* 成员变量随着对象的创建而创建,随着对象的回收而释放;
* 静态变量随着类的加载而加载,随着类的消失而消失;
*2.调用方法不同。
* 成员变量只能被对象调用;
* 静态变量可以被对象和类名两个调用;
*3.别名不同。
* 成员变量也被称为实例变量;
* 静态变量也被称为类变量;
*4.存储位置不同。
* 成员变量存储在堆内存的对象中,所以也叫对象的特有数据;
* 静态变量存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据;
*
*静态成员在实用中的一些细节:
*1.静态方法不能访问非静态成员,只能访问静态成员;非静态方法既可以访问静态成员也可以访问非静态成员;
*2.静态方法中不可以使用this关键字或者super关键字;
*3.主函数是静态方法,如果要访问非静态方法,就要先在主函数内创建一个对象,让对象去访问非静态方法。
静态变量:
当分析对象中所具备的成员变量的值是相同的,这是这个成员就可以被定义为静态成员。
只要数据在对象中都是不同的,就是对象的特有数据,
如果是相同的数据,对象不需要做修改,只需使用即可,不需要存储在对象中,定义成静态。
3.静态方法:
函数是否用静态修饰,只参考一点,就是该函数中的功能是否访问到对象中的特有数据。简单点说,从源代码看,该功能是否需要访问非静态的成员变量,如果需要,该方法就是非静态的。
4.静态代码块
1.随着类的加载,只运行一次。
2.静态代码块是给类进行初始化,有些类是不需要创建对象的,所以无法用构造器进行初始化,需要用静态代码块进行初始化。
3.给类进行初始化,用静态代码块,类里面的成员都是静态的。
4.静态代码块先执行,main方法后执行。
构造代码块:
可以给对象进行初始化。
代码的执行顺序’
静态代码块>构造代码块>构造方法
主函数
主函数的特殊之处:
* 1.主函数格式是固定的;
* 2.被Java虚拟机(JVM)识别和调用;
*
* public:因为权限是最大的;
* static:不需要创建对象,直接用主函数所属的类名所调用;
* void:主函数没有具体的返回值;
* main:函数名,不是关键字,只是一个JVM识别的固定名字;
* String[]:这是主函数的参数列表;是一个数组类型的参数,而且元素是字符串String型。
* args:参数名称,可以改变;
继承
继承的好处:
*1.提高了代码的复用性;
*2.让类与类产生了关系,给面向对象的第三个特征多态提供了前提;
*
*3.继承的体现方式:
*1.Java中只支持单继承,不支持多继承;
*单继承:一个子类只能有直接父类;
*多继承:一个子类可以有多个直接父类,Java不支持多继承;
*2.Java支持多层(多重)继承,c继承b,b继承a;
*就会出现继承体系;
*当要使用一个继承体系时:
*1.先查看该体系中的顶层类,了解该体系的基本功能;
*2.创建该体系中最底层子类对象,完成功能的使用;
*
*继承的误区:
*class DemoA{
*show1();
*show2();
*}
*
*class DemoB extends DemoA{//仅仅为了使用DemoA中的show(1)而继承DemoA;
*show(1);
*show(2);
*}
*误区就是仅仅为了使用别人的东西而继承,这样继承后DemoB就会有show(2);
*
*正确的写法是:
*class Demo{
*show(1);
*}
*
*class DemoA{
*show(2);
*}
*
*class DemoB{
*show(3);
*}
*
*什么时候定义继承?
*当类与类之间存在着所属关系的时候,就定义继承; xxx是XXX的一种;xxx extends XXX;
*
*所属关系:is a;
继承在代码中的体现:
* 1.成员变量
* 当父子类成员变量重名时,输出子类的成员变量;
*
* 当成员变量重名时,怎么操作父类的成员变量?
* 当本类的成员变量和局部的成员变量重名时,用this区分;当父子类的成员变量重名时,用super区分;
*
* this和super很相似;
* this代表一个本类对象的引用;
* super代表父类的空间;
*
* 当父类的成员变量私有时,子类就不能直接访问,只能通过父类的set、get方法访问。
*
/*
* 继承的代码体现
* 成员函数:
* 1.当子父类中出现成员函数一模一样的情况,会运行子类中的函数。这种现象称为覆盖操作;
* 覆盖只发生在父子类中。
* 2.重载和覆盖的区别(重点、面试):
* 重载发生在同一个类中,重载的英文名叫overload;
* 覆盖是发生在父子类中,覆盖也叫重写、覆写,覆盖的英文名叫override;
* 覆盖是发生在方法名、返回值类型、参数个数、参数类型完全一样的两个方法。
*覆盖的注意事项:
* 1.权限问题;
* 子类方法覆盖父类方法时,子类的权限要大于等于父类的权限;
* 2.静态只能覆盖静态或者被静态覆盖;
*什么时候用覆盖操作:
* 当对一个类进行子类的扩展时,子类需要保留父类的功能声明,但是要定义子类中该功能的特有内容时,就是用覆盖操作来完成;
*/
/*继承中的构造函数
* 在子类构造对象时,访问子类的构造函数时,父类的构造函数也运行了。
* 为什么?
* 原因是在子类的构造函数中,第一行有一个默认的的隐式语句super();
* 子类中所有的构造函数都会默认访问父类中的空参数构造函数;
*
* 为什么子类在实例化的过程中要访问父类的构造函数?
* 因为子类继承了父类,获取了父类的内容(属性),所以在使用父类中的内容之前,要先看父类是如何对自己的 内容进行初始化的,所以子类在创建对象时必须访问父类的构造函数。
*
* 为什么完成这个必须的动作,就要在子类的构造函数中加入super()语句?
* 如果父类中没有定义空参数的构造函数,那么子类的构造函数必须用super明确要调用父类中的那个构造函数。
* 同时,子类构造函数中如果使用了this调用了本类的构造函数,那么super()就没有,因为super()跟this()都只能定义在第一行,所以只能有一个存在。
* 注意:super()语句必须定义在子类构造函数的第一行,因为父类的初始化动作要先完成。但是,子类中肯定会有其他的构造函数访问父类的构造函数。
*
* this()与super()不能同时存在,两者只能存其一;
*
* Java中所有类都继承于Object;
*
* 一个对象的实例化过程:
* Person p = new Person();
*
* 1.Java虚拟机会读取指定路径下的Person.class,并加载进内存;并会先加载Person的父类(如果有直接父类的情况下);
* 2.在堆内存中开辟空间,分配地址;
* 3.并在对象空间中对对象中的属性进行默认初始化;
* 4.调用默认的构造函数进行初始化;
* 5.在构造函数中,在第一行会先调用父类中的构造函数进行初始化;
* 6.父类初始化完成后,再对子类的属性进行显示初始化;
* 7.就再进行子类构造函数的特定初始化;
* 8.初始化完成后,将地址赋值给引用变量;
final关键字
*
* final关键字:
* 1.final是一个修饰符,可以修饰类、方法、变量;
* 2.final修饰的类不能被继承;
* 3.final修饰的方法也不能被覆盖;
* 4.final修饰的变量是一个常量,只能被赋值一次;
*
* 加final修饰符一般前面都会加上static;
*
* 为什么要用final修饰变量,其实在程序中如果一个变量值是固定的,那么直接用这个数据就可以了,但是这样阅读性很差,所以给该数据起个名字,而且这个变量的值是不能改变的,所以加上final固定。