【JAVA_SE学习笔记】封装与继承
封装
权限修饰符:用于控制变量或方法的可见范围
public:公共,public修饰的变量或方法可以在任何范围内可见
private:私有的,private修饰的变量或方法只能在本类中可见
封装步骤: 1.用private修饰需要被封装的属性;
2.提供公共的方法设置或者获取该属性的值。
方法的命名规范:set属性名 或 get属性名
封装的好处: 1.提高了数据的安全性;
2.操作简单;
3.隐藏了实现。
封装的应用场景:
如果一个属性不想被其他人直接访问,可以使用封装。
avaBean:
是这样一类的类:
他的所有成员变量都使用private 进行修饰,并且对外提供可访问的设值和获取值的set,get方法。不同的应用场景,可能命名不同,数据库的应用中称为POJO类.
练习:
public class Demo3 {
public static void main(String[] args) {
Phone p=new Phone();
p.setNumber(110);
p.setType("摩托罗拉");
p.ring();
}
}
class Phone{
private long number;
public void setNumber(long number){
this.number=number;
}
public long getNumber1(){
return number;
}
private String type;
public void setType(String type){
this.type=type;
}
public String getType(){
return type;
}
public long getNumber(){
return number;
}
public Phone(){
}
public Phone(long number,String type){
setNumber(number);
setType(type);
}
public void ring(){
System.out.println(getType()+getNumber1()+"响了");
}
}
结果:
摩托罗拉110响了
public class Demo4 {
public static void main(String[] args) {
Student s=new Student();
s.setName("王五");
s.setAge(25);
s.setHight(175);
s.setSex("男");
s.getInformation();
}
}
class Student{
private String name;
private int age;
private int hight;
private String sex;
void setName(String name){
this.name=name;
}
void setAge(int age){
if(age>0&&age<150){
this.age=age;
}
}
void setHight(int hight){
if(hight>0){
this.hight=hight;
}
}
void setSex(String sex){
if(sex.equals("男")||sex.equals("女")){
this.sex=sex;
}
}
String getName(){
return this.name;
}
int getAge(){
return this.age;
}
int getHight(){
return this.hight;
}
String getSex(){
return this.sex;
}
public void getInformation(){
System.out.println("姓名:"+this.name+" 年龄:"+this.age+" 身高:"+this.hight+" 性别:"+this.sex);
}
}
结果:
姓名:王五 年龄:25 身高:175 性别:男
this关键字
this关键字代表的是所属函数的调用者对象
作用: 1.一个类存在同名的成员变量与局部变量时,在方法内部默认是访问局部变量的数据,可以通过this关键字访问成员变量的数据(构造函数中使用最多);
2.this关键字可以在构造函数中调用其他的构造函数初始化对象。
注意:
1.如果在一个函数中访问一个成员变量,且不存在同名的局部变量时,java编译器会默认在变量前加上this关键字;
2.this关键字调用其他构造函数时,this语句必须位于构造函数中的第一个语句;
3.this关键字调用构造函数时不准出现相互调用的情况,因为是一个死循环的调用方式。
举例:
class Animal{
int id; // 编号
String name; //成员变量
String color; //颜色
public Animal(int id,String name,String color){
//this(); //调用了本类无参的构造函数。
this(name,color); //调用到两个参数的构造函数
this.id = id;
}
//构造函数
public Animal(String name,String color){ //形式参数也是属于局部变量。
this.name = name;
this.color =color;
}
// this关键字代表的是所属函数的调用者对象。
public void eat(){
String name = "猫"; //局部变量
System.out.println(this.name+"在吃饭...");
}
}
static(静态)关键字
static修饰成员变量:
如果一个数据需要被所有对象共享使用时,即可使用static修饰该成员变量
访问方式: 方式一:可以使用对象进行访问
格式:对象.静态属性名
方式二:可以使用类名进行访问
格式:类名.属性名
注意:
1.静态的成员变量可以使用类名或对象进行访问;
2.非静态的成员变量只能使用对象访问;
3.千万不要为了方便访问而使用static修饰一个成员变量,只有这个成员变量的数据是需被共享时才使用static修饰。
static修饰成员函数:
访问方式: 方式一:使用对象访问
格式:对象.函数名()
方式二:使用类名访问
格式:类名。函数名()
注意:
1.静态函数可以直接访问静态的成员,但不能直接访问非静态的成员;
2.非静态函数可以直接访问静态及非静态的成员;
3.非静态函数只能用对象调用;
4.静态函数不能出现this、super关键字。
静态数据是优先于对象而存在的
原因:
1.静态函数可以使用类名调用,而这时对象可能还没有存在内存中,这时非静态数据也就不在内存中;
2.非静态函数必须由对象调用,如果对象存在了,静态数据及非静态数据早就存在内存中了;
3.静态函数可以使用类名直接调用,这时可能还没有对象存在,this又要代表当前对象,矛盾。
非静态成员变量与静态成员变量的区别:
1.数量上的区别:非静态成员变量是在每个对象中都维护一份数据(n份)
静态成员变量只会在方法中维护一份数据(1份)
2.访问对象的区别:非静态成员变量只能用对象进行访问
静态成员变量可以使用对象、类名进行访问
3.存储位置的区别:非静态成员变量存储在堆内存中
静态成员变量存储在方法区中
4.生命周期的区别:非静态成员变量随着对象的创建而存在,随着对象的消失而消失
静态成员变量随着类文件(字节码文件)的加载而存在,随着类文件的消失而消失
5.作用上的区别:非静态成员变量作用是描述一类事物的属性
静态成员变量作用是提供一个共享数据给对象使用
使用场景: 如果一个函数没有直接访问非静态的成员变量,即可使用static修饰该函数(常用于工具类的方法)
举例:
public class Demo6 {
public static void main(String[] args) {
Quadrate q=new Quadrate();
q.setSideLength(10);
System.out.println("周长为:"+QuadrateMath.perimeter(q));
System.out.println("面积为:"+QuadrateMath.acreage(q));
}
}
class Quadrate{
private int sideLength;
public void setSideLength(int sideLength){
this.sideLength=sideLength;
}
public int getSideLength(){
return this.sideLength;
}
}
class QuadrateMath{
private QuadrateMath(){
}
public static int perimeter(Quadrate q){
return(q.getSideLength()*4);
}
public static int acreage(Quadrate q){
return(q.getSideLength()*q.getSideLength());
}
}
结果:
周长为:40
面积为:100
main方法详解
public static void main(String [] args){
}
main方法是由jvm调用的,jvm也是一个程序
public:公共。保证该类在任何情况下,jvm都对其方法可见
static:静态。用类名调用,避免创建对象,解决了创建对象传递参数问题
没有static修饰的结果:
1.jvm调用main方法时需创建对象
2.创建对象需要的参数(无法解决)
void:没有返回值。即使有返回值,也是返回给jvm,jvm对这个返回值没有作用
main:不是关键字,只是jvm标识的一个特殊的标识符
args:形参,某些程序在启动时需要一些参数
继承
格式:
class 类名1 extends 类名2{
}
注意:
1.子类可以继承父类的成员,但不要为了减少重复代码而去继承,只有真正存在继承关系的情况才能去继承;
2.父类私有的成员是不能被继承的;
3.父类的构造方法也是不被被继承的;
4.创建子类对象时默认先调用父类无参的构造函数。
调用父类的构造方法作用是为了初始化从父类继承的属性
继承优点:
a.提高了代码的复用性
b.提高了代码的维护性
继承缺点: 类的耦合性增强了。
开发的原则:
高内聚,低耦合.
耦合: 类和类之间的关系
内聚: 自己独立完成某件事情的能力.
super关键字
super关键字代表的是父类的引用空间
作用:
1.如果子父类存在同名的成员时,在子类中默认访问子类的成员,可通过super指定访问父类的成员;
2.可以在子类的构造函数中指定调用父类的构造方法。
创建子类对象时,默认先调用父类无参的构造方法
举例:
class Fu{
int x = 10;
String name;
public Fu(String name){
this.name = name;
System.out.println("父类带参的构造函数....");
}
public Fu(){
System.out.println("父类无参的构造函数....");
}
}
//子类
class Zi extends Fu{
int x = 20;
public Zi(String name){
super(name); //调用父类一个参数的构造函数...
//this(); //调用本类无参的构造函数
System.out.println("子类构造函数....");
//super(); //调用了父类无参的构造函数....
}
public Zi(){}
public void print(){
super.eat();
System.out.println("x:"+super.x); // 10
}
}
注意:
1.super关键字调用构造方法时,必须是构造方法中的第一句;
2.super,this调用构造方法时,不能同时出现在同一个构造方法中(因为两者都需要是第一个语句)
方法重写
父类的功能无法满足子类的需求,需进行方法的重写
子父类存在同名的方法称作方法重写
要求:
1.子父类的方法名与形参列表必须一致
2.子类的权限修饰符必须要大于或者等于父类的权限修饰符
3.子类的返回值类型必须小于或等于父类的返回值类型
4.子类抛出的异常类型必须小于或者等于父类抛出的异常类型
举例:
public class Demo3 {
public static void main(String [] args){
Quadrate q=new Quadrate(2);
System.out.println("正方形边长为:"+q.perimeter());
System.out.println("正方形面积为:"+q.acreage());
Rectangle r=new Rectangle(2,5);
System.out.println("长方形边长为:"+r.perimeter());
System.out.println("长方形面积为:"+r.acreage());
}
}
class Quadrate{
int sideLength;
public Quadrate(int sideLength){
this.sideLength=sideLength;
}
public Quadrate(){
}
public int perimeter(){
return (sideLength*4);
}
public int acreage(){
return (sideLength*sideLength);
}
}
class Rectangle extends Quadrate{
int longLength;
public Rectangle(int sideLength,int longLength){
//子类构造函数默认调用父类无参的构造函数,所以父类一定要有无参的构造函数
super(sideLength);
this.sideLength=sideLength;
this.longLength=longLength;
}
public int perimeter(){
return (longLength+sideLength)*2;
}
public int acreage(){
return (longLength*sideLength);
}
}
结果:
正方形边长为:8
正方形面积为:4
长方形边长为:14
长方形面积为:10