封装:(信息隐藏)/代码复用
将事物的属性和方法写进类里面
但是在类中定义属性的时候,一般需要把属性隐藏起来。
如果外界需要访问这个属性,那么就提供公共方法对其访问
public class Student{
//使用private关键字来修饰属性,不允许外部直接访问该属性
private String name;
//提供公共的setName方法,可以让外部调用该方法给name属性赋值
public void setName(String name){
this.name = name;
}
//提供公共的getName方法,可以让外部调用该方法获取name属性的值
public String getName(){
return name;
}
}
private 修饰符的特点:
private是四种权限修饰符中的一种,并且是权限最小的一种
private可以修饰成员变量和成员方法
private修饰成的属性和方法,就只在当前类中才能访问,在当前类以外的其他地方,都不能访问
private修饰的属性,称为类中的私有属性,private修饰的方法,称为类中的私有方法
封装的优点:
-
提高代码的安全性,重要信息可以私有化,不对外暴露
-
提高代码的复用性,常用的代码或者功能封装到方法中,可以在其他地方反复调用
-
封装代码的实现细节,便于修改内部代码,提高可维护性
-
简化外部的调用,便于调用者使用
其实,我们在定义一个类的时候,就是在完成封装的过程。
关于类中的属性命名:
Field(实例变量属性,字段属性)
Property(引用变量属性,方法属性)
attribute
方法重载(在一个类里面写同样名字的方法但是传入的参数不同)
类中有多个方法,具有相同的方法名,但是方法的参数各不相同,这种情况被称为方法的重载 (overload(ing))
方法的重载,必须是在同一个类中,并且要求如下:
-
方法的名字必须相同
-
方法的参数列表必须不同
参数的类型不同
参数的个数不同
参数的顺序不同
(int s,String i)和(int i ,String s)相同,
和(String s,int i)不同
- 方法的修饰符、返回类型、抛出异常这些地方没有限制(可以相同,也可以不同,但一般都是相同的)
public class Test{
//参数的个数不同
public void test(){}
public void test(int a){}
public void test(String s1,String s2){}
//参数的类型不同
public void test(boolean flag){}
public void test(double salary){}
//参数的顺序不同
public void test(int a,String s){}
public void test(String s,int a){}
//方法的参数可以相同,也可以不同
public int test(int a,int b){
return 0;
}
}
方法的重载与重写的区别
语法
1.出现的位置
重载发生在本类,重写发生在父类与子类之间;
2.相同的,不同的
重载的方法名必须相同,重写的方法名相同且返回值类型必须相同;重载的参数列表不同,重写的参数列表必须相同
编码的时候
重载
构造器
类中的构造器也称为构造方法、构造函数,是在创建对象的时候必须要调用的
构造器有以下俩个特点:
必须和类的名字保持一致
必须没有返回类型,也不能写void
public class 类名{
***public 类名(){}/***/如果类中一个构造器都没有定义的话,jvm会给你创建一个无参构造器,用于创建对象时调用,如果一旦有任何一个构造器,默认的构造器就不存在。
}
构造器的作用:
使用new关键字来创建对象的时候,后面跟的必须是类中存在的构造器
构造器中的代码,在对象创建后会被调用,从而可以完成对象的初始化工作
public class Student{
private String name;
private int age;
//构造器
public Student(String name,int age){
this.name = name;
this.age = age;
}
public static void main(String[] args){
//创建对象的时候使用构造器
//并且传参到构造器中,构造器中可以使用这些参数给属性进行初始化
Student stu = new Student("tom",20);
}
}
构造器可以重载,称为构造器重载
除了默认的无参构造器之外,在类中还可以对构造器进行重载,让构造器可以接收一些参数,然后使用这些参数进行对象的初始化工作。
public class Student{
private String name;
private int age;
//无参构造器
public Student(){}
//有参数构造器,接收参数,进行对象属性的初始化
public Student(String name){
this.name = name;
}
public Student(int age){
this.age = age;
}
public Student(String name,int age){
this.name = name;
this.age = age;
}
}
构造器之间的调用:
使用this关键字,可以在构造器中,调用另一个构造器
前提是不能递归调用(两个构造器互相调用)
public class Student{
private String name;
private int age;
//无参构造器
public Student(){
//调用俩参的构造器
this("tom",20);
}
public Student(String name){
//调用俩参的构造器
this(name,0)
}
public Student(int age){
//调用俩参的构造器
this(null,age);
}
public Student(String name,int age){
this.name = name;
this.age = age;
}
}
继承
类与类的关系的一种,其余的还有依赖,组合,聚合
继承描述的是事物之间的所属关系,这种关系是: is-a 的关系。
子类继承父类,子类就可以继承父类中定义的属性和方法。
例如,
蛇属于爬行动物,爬行动物属于动物。
爬行动物继承了动物的基本属性和方法,蛇又继承了爬行动态的基本
属性和方法。
由此可见,父类更通用,子类更具体。
子类继承父类,使用关键字 extends
//定义Person类,作为父类
public class Person{
String name;
public void sayHello(){
System.out.println("hello~ I am "+name);
}
}
//定义Student类,作为子类
class Student extends Person{
}
public static void main(String[] args){
Student stu = new Student();
stu.name = "tom";//name属性从父类中继承而来
stu.sayHello();//sayHello方法从父类中继承而来
}
父类中的私有属性和方法,子类中不能访问。
注意,父类中的构造器,子类是不能继承的。
java中,类与类之间的继承一对一,没有继承默认继承父类Object
super关键字(父类中的this)
在子类中,使用super关键字一般做以下事情:
访问父类中的属性
调用父类中的方法
调用父类中的构造器
public class Person{
String name = "zs";
}
public class Student extends Person{
//注意,这里是故意和父类中的属性重名
String name = "lisi";
public void test(){
//直接使用name,表示Student中的name属性(就近原则)
System.out.println(name);
//也可以使用this和super来区分访问的是哪个name
System.out.println(this.name);//Student中的name
System.out.println(super.name);//父类Person中的name
}
}
public class Person{
public void run(){
System.out.println("person run..");
}
}
public class Student extends Person{
//注意,这里是故意和父类中的方法重名
public void run(){
System.out.println("student run..");
}
public void test(){
//直接使用name,表示Student中的run方法(就近原则)
run();
//也可以使用this和super来区分调用的是哪个run方法
this.run();
super.run();
}
}
子类与父类的构造器关系(一定会调用)
如果父类构造器有参,则调用父类的构造器必须显式调用
public class B{
/*public B {}//父类无参构造器*/
}
public class A extens B{
/*public A{
super();//父类无参构造器
}*/
}
重写(重写父类的某个方法)override
重写(访问不能被缩小(父类的public不能被重载成private),异常不能被扩大(父类的indexoutofdboundsexception不能被重载成exception))
子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。
构造方法不能被重写
to String 方法
在JavaAPI中,String类继承了Object,并且重写了Object类中的toString、equals等方法:
注意,Object所所有类的父类,每一个类都是直接或间接继承了Object类
一般什么情况下,我们会在子类中,对从父类继承的方法进行重写?
子类继承父类,继承了父类中的方法,
但是父类中的方法并不一定能满足子类中的功能需要,
所以子类 中需要把方法进行重写。
多态:
相同类型的不同对象,调用同一个方法,最终执行结果是不同的
java中的多态,就是来描述这种情况的。
多态的前提:
子类继承父类
子类重写父类中的方法
父类的引用指向子类对象
拿父类的引用指向子类的对象也是一种多态(编译时多态)
Employee e = new Manager();//面向父类编程
method(父类 e){
}
e.method(); //method要在父类中或者父类的父类中声明,子类有不行
父类类型的引用可以调用父类中定义的所有属性和方法,而对于子类中定义而父类中没有的方法,父类引用是无法调用的;
当父类中的一个方法只有在父类中定义而在子类中没有重写的情况下,才可以被父类类型的引用调用; 对于父类中定义的方法,如果子类中重写了该方法,那么父类类型的引用将会调用子类中的这个方法,这就是动态连接
运行时多态
r.多态();
instanceof
instanceof能告诉我们,当前父类的引用, 到底是执行的哪一个子类对象(必须存在子父类关系)
public class Person {
}
class Student extends Person{
}
class Teacher extends Person{
}
public void test(Person p){
//引用p到底是指向的Student对象还是Teacher对象呢??
}
public void test(Person p){
if(p instanceof Student){
//说明p指向的是Student类型对象
}
else if(p instanceof Teacher){
//说明p指向的是Teacher类型对象
}
}
引用类型的转换
向上转型(子类转父类)
多态本身就是将子类的对象赋值给父类的引用,这就是一个自动向上转型的过程(类型自动转换)
例如, Person p = new Student();
向下转型(父类转子类)
父类类型向子类类型转换,是向下转换的过程。(类型强制转换)
例如,
Person p = new Student();
Student s = (Student)p; //向下转型,为了调用到Student的方法
引用类型强制转换时的异常: 在类型强制转换的过程中,可能会遇到类型转换异常,
public class Person {
}
class Student extends Person{
//注意,这是子类中单独定义的方法,和父类无关
public void study(){}
}
class Teacher extends Person{
}
public static void main(String[] args) {
Person p = new Teacher();
//编译通过,运行报错!
//错误类型是:ClassCastException(类型转换异常)
//Student和Teacher之间没有父子关系
Student s = (Student)p;
s.study();
}
所以转换之前要先用instanceof判断
public static void main(String[] args) {
Person p = new Teacher();
//如果引用p真的是指向Student类型的对象,那么才进行类型的强制转换
//避免在强制转换的过程中出现ClassCastException类型的异常
if(p instanceof Student){
Student s = (Student)p;
s.study();
}
}
数据类型转换
基本数据之间(精度)
引用类型之间
1.存在子类关系
隐式转换:子类对象赋值给父类对象引用
显式转换:(编译没问题) 父类转子类 instanceof == true转
2.不存在子类关系
要转的两种类型是否有提供方法,没有看是否有中间类帮忙,还没有就不能转。