学习资料来源:阿里云大学 Java面向对象编程 魔乐科技软件学院
其它笔记将更新在此笔记:Java学习笔记
封装性:内部的操作对外部而言不可见
继承性:在已有结构的基础上继续进行功能的扩充;。
多态性:是在继承性的基础上扩充而来的概念,指的是类型的转换处理。
类是一个模版,而对象才是类可以使用的实例,先有类再有对象。
类的组成:
new:用于开辟新的空间
如果要进行内存分析,那么首先给出两块最为常用的内存空间:
堆内存:保存的是对象的具体信息,在程序之中堆内存空间的开辟是通过new完成的
栈内存:保存的是一块堆内存的地址,即:通过地址找到堆内存,而后找到对象内容,但是为了分析简化,可以简单地理解为:对象名称保存在栈内存中
所有对象必须在实例化之后才能执行,程序中出现的NulPointerException异常,就是在没有堆内存开辟之后产生的问题,并且只有在引用数据类型存在此问题。
类本身属于引用数据类型,既然是引用数据类型,那么就牵扯到内存的引用传递,所谓的引用传递的本质:同一块堆内存空间可以被不同的栈内存所指向,也可以更换指向。
Person per1 = new Person();
Person per2 = per1 ;
引用传递可以发生在方法上,这个时候一定要观察方法的参数类型,同时也要观察方法的指向过程。
所谓的垃圾空间指的就是没有任何栈内存所指向的堆内存空间,所有的垃圾将被GC定期进行回收并且释放无用内存,但是垃圾过多,一定会影响GC。
**构造方法:**可以通过构造方法实现实例化对象中的属性初始化处理
**构造方法的重载:**只需考虑参数的个数和类型,其它不变
匿名对象:如果值通过实例化对象来进行类的操作,那么这种形式的对象由于没有名字称为匿名对象。
new Person(“zhangsan",10); // 匿名对象
此时依然通过了对象进行了类中tell()方法的调用,但是由于此对象没有任何引用名称,所以该对象使用一次就变成垃圾,而所有的垃圾将被GC进行回收与。
在你以后所编写的程序代码之中,只要是访问本类中属性的时候,请一定要加上“this"。
对于本类构造方法的互相调用需要注意以下几点重要问题:.
static属性可以由类名称直接调用。
static属性虽然定义在类之中,但是其并不受到类实例化对象的控制。static属性可以在没有实例化对象时使用
当考虑的公共信息存储的时候,使用static。有点类似全局变量
static定义的方法或者是属性都不是你代码编写之初所需要考虑的内容,只有在回避实例化对象调用并且描述公共属性的情况下才会考虑使用static定义的方法或者是属性。
普通代码块的主要特点是定义在一个方法之中的代码块。
构造块会优先于构造方法执行,并且每一次实例化新对象的构造块中的代码。
执行结果:
aaaaaaa
hhhhhh
aaaaaaa
hhhhhh
静态代码块优先与构造块执行,并且只执行一次,目的是为了静态属性初始化。
数组是引用类型,一定要在堆中开辟空间才能使用。
排序:Arrays.sort();
拷贝:System.arraycopy();
例:public int sum(int … data){} // 参数个数可变,本质上依然属于数组
数组中的元素是对象,这样的数组就是对象数组。
class Car{ private String name; private double price; private Person person ; public Car(String name, double price) { this.name = name; this.price = price; } public String getInfor(){ return "车牌:"+name+" 价格"+price; } // setter getter public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } } class Person{ private String name; private int age; private Car car; public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getInfor() { return "车主:"+name+" 年龄: "+age; } // setter getter public String getName() { return name; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } public class Test { public static void main(String[] args) { Person person = new Person("张三", 20); Car car = new Car("劳斯莱斯", 80000000); // 创建关联关系 person.setCar(car); // 一个人有一辆车 car.setPerson(person); // 一辆车属于一个人 // 根据关系获取数据 System.out.println(person.getCar().getInfor()); // 车的信息 System.out.println(car.getPerson().getInfor()); // 车主的信息 } }
class Car{ private String name; private double price; private Person person ; public Car(String name, double price) { this.name = name; this.price = price; } public String getInfor(){ return "车牌:"+name+" 价格"+price; } // setter getter public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } } class Person{ private String name; private int age; private Car car; private Person[] children; // 一个人有多个孩子 public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getInfor() { return "车主:"+name+" 年龄: "+age; } // setter getter public Person[] getChildren() { return children; } public void setChildren(Person[] children) { this.children = children; } public String getName() { return name; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } public class Test { public static void main(String[] args) { Person person = new Person("张三", 20); Car car = new Car("劳斯莱斯", 80000000); Person childA = new Person("儿子", 12); Person childB = new Person("女儿", 10); childA.setCar(new Car("宝马", 30000)); // 匿名对象 childB.setCar(new Car("奥迪", 40000)); // 匿名对象 person.setChildren(new Person[]{childA,childB}); // 一个人有孩子 // 创建关联关系 person.setCar(car); // 一个人有一辆车 car.setPerson(person); // 一辆车属于一个人 // 查看一个人的孩子信息和孩子的汽车 for(int i = 0; i<person.getChildren().length;i++){ System.out.println("名字:"+person.getChildren()[i].getName()); System.out.println("\t "+person.getChildren()[i].getCar().getInfor()); } } }
继承的本质:在原有类的基础上继续进行扩充
子类又称作派生类,父类称作superClass
extends
super()表示的就是子类构造调用父类构造的语句,该语句只允许在首行,默认情况下调用无参构造,但是若父类没有无参构造,则子类必须利用super明确调用有参构造。
无论你如何折腾,在实例化子类对象的同时一定会实例化父类对象,目的是为了所有的属性进行空间分配。
this是调用本类构造方法,super是调用父类构造方法,都是放在首行,因此不能同时出现。
方法名称和父类相同,但是参数类型和个数、返回值相同,就叫做覆写。
由于现在实例化的是子类对象,所以此时调用的方法一定是被子类所覆写过的方法,如果该方法没有被覆写过。那么将调用父类中提供的方法,覆写的意义是在于:优化父类的功能。.
在子类进行方法覆写之后如果现在要想继续调用父类中的方法,那么就必须使用“super.方法()”。
只要是在子类中调用父类方法的时候一定要在方法前追加有“super.方法”
当子类定义了与父类相同名称的成员时候就称为属性覆盖。(如果属性封装了,那么此时就不是属性覆写)
super vs this
final定义不能被继承的类。
final定义不能被覆写的方法和常量。
final用于定义常量。
实际上常量通常是公共的共享的,因此常常使用public static final int ON = 1;这样来定义常量。
class Person{ private String name; private int age; private String sex; public Person(String name){ this.name = name; } public Person(String name, int age, String sex) { this(name); this.age = age; this.sex = sex; } public String getInfor(){ return "姓名:"+name+"\t年龄:"+age+"\t性别:"+sex; } } class Student extends Person{ private String school; private String grade; public Student(String name, int age, String sex,String school,String grade) { super(name, age, sex); this.school = school; this.grade = grade; } public String getInfor(){ return super.getInfor()+"\t学校:"+school+"\t年级: "+grade; } } public class Test { public static void main(String[] args) { Student student = new Student("Bobo", 12, "man", "LNU", "se"); System.out.println(student.getInfor()); } }
利用Annotation可以有效减少程序配置的代码,并且可以利用Annotation进行一些结构化的定义。Annotation是以一种注解的形式实现的程序开发。
利用注解可以减少一些配置文件。
可以在明确要覆写的方法上,增加一个@Override
该注解可以帮助开发者在程序编译的时候检查出问题的错误(比如要覆写的方法名写错了)。
所谓的过期操作指的是在一个软件项目的迭代开发过程之中,可能有某一个方法或者是某个类,由于在最初设计的时候考虑不周到(存在有缺陷),导致新版本的应用会有不适应的地方(老版本不影响),这个时候又不可能直接删除掉这些操作,那么就希望给一个过渡的时间,于是采用一个过期的声明,目的是高斯新的用户这些操作不要再用了,老的用户用了就用了,这样的方法必须使用@Deprecated进行定义。
就是让警告信息不出现,不骚扰你。
大多数是向上转型
向上 转型的优势:对参数进行统一的设计(接收或返回参数的统一性)。
关键:实例化的是哪个子类、以及子类有没有进行方法的覆写。
class Person{ private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public void print(){ System.out.println("I am a Person!"); } } class Student extends Person{ public Student(String name, int age) { super(name, age); } public void print(){ // 方法覆写 System.out.println("I am a student!"); } } class Teacher extends Person{ public Teacher(String name, int age) { super(name, age); } public void print(){ // 方法覆写 System.out.println("I am a teacher!"); } } public class Test { public static void main(String[] args) { fun(new Student("Bob", 12)); // 子类向上转型 fun(new Teacher("LIi", 22)); // 子类向上转型 // 通过向上转型,如果有n个子类的话,在进行调用的时候, // 也只需要fun这一个方法 } public static void fun(Person person){ person.print(); } }
向上描述的是一些公共的特征,而向下描述的是子类自己特殊的定义环境,但是需要明确的是,向下转型并不是一件安全的事情。因为在进行向下转型之前一定要首先发生向上转型。
class Person{ public void print(){ System.out.println("I am a Person!"); } } class Superman extends Person{ public void print(){ System.out.println("I am a Superman!"); } public void fly(){ System.out.println("I can fly!"); } public void fire(){ System.out.println("I can fire!"); } } public class Test { public static void main(String[] args) { Person person = new Superman(); // 向上转型 person.print(); // 他首先是一个超人,但是正常情况下他处于正常人的状态 // 一旦有超人的需要,就进行变形(向下转型),可以飞行和喷火 Superman superman = (Superman)person; // 向下转型 superman.fly(); superman.fire(); } }
向下转型是为了使用子类的功能
为了保证向下转型的安全,需要使用instanceof进行判断。
public class Test { public static void main(String[] args) { Person person = new Superman(); // 向上转型 if(person instanceof Superman){ // 转型之前先判断 Superman superman = (Superman)person; // 向下转型 superman.fly(); superman.fire(); } } }
Object类的主要特点是可以解决参数的统一问题,也就是说使用Object类可以接收所有数据类型。
在Java之中只有一个类是不存在有继承关系的,那么这个类就是Object。
如果一个程序的方法要求可以接收所有类对象的时候就可以利用Obiect实现处理,但需要注意,在Java设计中,对于所有的引用数据类型实际上都可以使用Object类进行接收,包括数组。
toString(); // 用于获取对象信息,默认情况下不写
在父类设计的时候,优先考虑使用抽象类
抽象类的主要作用在于对子类中覆写方法进行约定,在抽象类里面可以去定义一些抽象方法以实现这样的约定,抽象方法指的是使用了abstract关键字定义的并且没有提供方法体的方法。(在普通类的基础上追加抽象方法就是抽象类)
抽象类不能直接实例化
包装类的主要功能是针对于基本数据类型的对象转换而实现的,并且随着JDk改变而进行改变。
class Int{ private int data; // 包装一个基本数据类型 public Int(int data){ this.data = data; } public int intValue(){ return this.data; } } public class Test { public static void main(String[] args) { Object obj = new Int(10); // 装箱:基本数据类型包装 int x = ((Int)obj).intValue();// 拆箱:从包装类中去数据类型 System.out.println(x); } }
现在可以发现在Java 中包装类一共提供有两种类型:
Number类是一个抽象类,这个类有六个方法。
数据装箱:将基本数据类型保存到包装类之中,一般可以利用构造方法完成
数据拆箱:从包装类中获取基本数据类型:
数值型包装类已经由Number类定义了拆箱的方法了;
Boolean型: public boolean booleanValue();
public class Test { public static void main(String[] args) { Integer obj = new Integer(10); // 装箱 int x = obj.intValue(); // 拆箱 System.out.println(x); } }
public class Test { public static void main(String[] args) { Integer obj = 10; //自动装箱 int x = obj; // 自动拆箱 System.out.println(x); } }
以后进行包装类相等判断的时候一定要使用equals()完成