首先给我们日常的编程方法下定义,面向过程,是分析问题并将问题拆解,逐步实现的过程,在过程中处理问题直接调用方法,该过程效率高。
面向对象则是描述事物在解决问题的过程中发生的行为,该方法在工程上的特征是易维护、易复用、易拓展,可以设计出低耦合的系统,性能上来说比面向过程要低。
由此可以看出面向对象,实质是针对工程大型化和便于分工合作的情况下在效率的妥协,其特征是封装,继承,多态。
类的定义应包含成员变量和方法,有些变量比如密码,ID,住址等隐私性较强,不希望外部轻易获取,故不同的变量应采取不同的权限,但我们可能没法区分信息的私密性。故工程规定,所有变量均使用private
权限,即只能在当前类内获取,需要提供对外访问服务的编写方法实现。
不同权限修饰符作用域如下:
public 当前工程内可用
protected 不同包的子类可用
default 同一个包内可用
private 只有类内可用
封装是将逻辑方法封装在类的内部,对外提供访问权限的思想。
类内包含的元素有:
属性,普通方法,构造方法,get和set方法,toString方法。
方法可以通过对象直接调用,但成员变量不可,需要在变量前加public修饰。
构造方法是创建对象时自动调用的方法,在没规定时会默认有一个无参构造函数,编写构造函数后,无论有参无参都覆盖默认构造函数,所以当对象不能存在无参时,可以写有参构造来覆盖原有函数,避免无参构造。
构造语法:public 类名(){}
,有参构造是在创建对象的同时给类中的各属性赋值,构造函数支持重载。
提供给外部的接口,get用于查询可公开的成员变量,set用于输入可公开的成员变量,在IDEA中可使用alt+insert快捷键快速生成。
引用数据类型直接输出时默认调用执行的方法,来自Java内部的一个类,可以自行改写,示例如下:
public class student {
private String name;
private int id;
}
public String toString(){
return this.name+" "+this.id;
}
在如下代码中可以输出toString函数内容
public class demo {
public static void main(String[] args) {
student student=new student("kevin",317520);
System.out.println(student.toString());
}
}
可用用于修饰属性,方法和代码块,修饰的属性在类被加载时放入方法区,先于对象存在,无论有没有对象都有它;修饰的方法可以通过类直接调用,二者都只加载一次,修饰的内容放到方法区,不回收占用的空间,故只有常用的变量和方法才用static
修饰,感觉与C中的const
差不多。
修饰代码块在类加载时加载,优于主函数,即在主函数执行前执行,示例如下:
public static void main(String[] args) {
System.out.println("main progress is working!");
}
static {
System.out.println("static progress is working!!!");
}
//输出结果为
static progress is working!!!
main progress is working!
继承用于扩充已有类的功能,语法class A extands B
Java中只有单继承,即一个类只能继承一个父类,子类有父类的全部方法,但修饰符为private
的无法继承,所有类默认直接或间接继承object
类。
子类在创建实例时会自动创建父类实例,即在自身构造函数的第一行会自动加上super()
,`代码展示现象如下:
public class demo {
public demo(){
System.out.println("demo is working!");
}
public static void main(String[] args) {
a ab=new a();
}
}
class a extends demo{
public a(){//默认隐含super()
System.out.println("a is coming!!!");
}
}
//输出结果为
demo is working!
a is coming!!!
super
是指向父类的实例,有super.成员变量
和super()
两种使用方法,可以在子类构造中添加父类的有参构造,来覆盖其隐含无参构造。
重写是指父类和子类有同名方法的现象,当父类方法不满足子类需求时,子类可以重写父类方法的业务逻辑。
重载和重写的区别如下图:
定义的类不能被继承
定义的基本属性值不变,引用数据类型的地址不能发生变化
定义的方法不能被覆写
程序运行期间值不可改变的量,通过static final
两个关键字来定义,命名规范为:名称全部大写,单词间用下划线连接,具体解读为:static
类加载,只加载一次,在方法区开辟空间;final
最终,定义的量值不能发生变化,效果与C中的const
类似。
但是如果单单只要实现值不可改变,仅使用final
就可实现,static
的意义何在呢?
这要从我们一直讲但是很少用的内存分布来解释,对象的内存开辟在jvm的堆中,每个对象的每个成员变量都需要开辟,如果一类对象的某个或者某些的成员变量都一致时,能不能想办法整合呢?由此我们想到了利用static
定义的量在方法区中只加载一次的特性,避免了相同内容的重复开辟,节约了jvm的内存。
因此我们确定常量的原则应该是,值不变,且重复性高。
多态指一个行为具有多个不同表现形式或形态的能力,具体表现为Java允许父类的引用指向子类的对象,代码示例如Animal animal=new Dog()
,由父类的animal
接受子类Dog
创建的对象。
多态又分为向上转型和向下转型,上文提到的是向上转型,向下转型则类似于强制类型转换,形如Dog dog=(Dog)animal
,将父类animal
强制转换为子类Dog
,一般用于调用子类的私有方法。
但两个级别相同的类不可类型转换,如Dog
转为Cat
,所以在向下转型时应使用instanceof
方法,对象 instanceof 类名
用于判断实例是否属于类,判断后再强制转换。
多态的使用有三个前提条件:
有继承关系
有方法重写
父类的引用指向子类对象
多态是面向对象最重要的特征,使用多态设计程序可以提高程序的扩展力。在编程设计模式中有相当重要的设计模式原则—ocp(对扩展开放,对修改关闭)。因为模块直接有耦合性,单一人员不一定对项目有准确的整体把握,所以在设计程序时不可修改工程中的原有代码,但可以在原有代码的基础上进行类、接口和模块的扩展。
多态在使用时很少直接出现严格父类接受子类的情况,往往是隐式的多态,可以出现在形参,方法的返回值和成员变量中,主要思想是用一个父类接受多个子类,避免修改原有函数而只用父类作参数,接受新的子类。
抽象类是通过abstract
修饰的类,本身无法实例化对象,但是可以基于多态的方式创建对象,抽象类可以包含抽象方法(通过abstract
修饰的方法,没有方法体,用来被子类重写且必须被重写,可被子类继承)、构造方法(用于被子类指向)、普通成员变量和普通方法。
使用不多,与常规类相比没什么优点,可能是专门用来限制不能实例化的基类。
抽象类中的抽象方法需要被重写,但仍可以有普通方法和成员变量,接口是完全隐藏其内部,只有常量和抽象方法的结构(也有可以有静态方法,但很少用),因为接口中只能包含抽象方法,故定义抽象方法的public abstract
可以省略。
接口是引用数据类型,类加载时生成字节码文件,通过interface A{}
定义,类可实现接口,就是类的继承,通过class B implements A
实现,接口可多实现,即一个类可实现多个接口,就是在类中重写多个接口的方法。
是目前的编程规范,基于接口的编程,在类中实现接口功能,利用多态调用。从结构来说接口确实名副其实,上游根据接口名称编写功能,下层开发者通过接口名称调用功能部分代码,接口起到一个中间层的作用,确实像是接口,连接上下双方。
定义在另一个内部的类,语法举例,A的内部类B,A.B ab=new A().new B()
new 接口/父类(){重写方法}
,实质是创建接口对应的匿名子类,可直接在return中返回一个未命名的接口实例。
面向对象三大特性,封装、继承、多态,都是为了工程性和做出的效率妥协,其中
封装是为了实现高内聚低耦合
继承是为了减少重复开发
多态是为了在保证稳定性的前提下提高代码拓展力