Java面向对象
Java是面向对象的程序设计语言,提供定义类,属性,方法的基本功能.面向对象的三大特征:封装,继承,多态
1. 类和对象
类是面向对象的重要内容,可以把类当作一种自定义数据类型,使用类定义变量,这种变量类型都属于引用类型变量.类就是引用数据类型
1. 定义类:
[修饰符] class 类名{
//0个或多个方法
//0个或多个属性
//0个或多个构造方法
}
每个类在没有定义构造方法的时候系统都会默认为该类提供一个无参的构造方法.
2. 定义属性:
[修饰符] 属性类型 属性名 [=默认值];
修饰符可以省略,也可以是public,private,protected,static,final.其中public,private,protected三个只能选其一,可与static和final组合起来修饰属性.
属性类型可以是Java允许的任意数据类型,包括基本数据类型和引用类型.
属性名是任意合法字符即可.
3. 定义方法:
[修饰符] 返回值类型 方法名(形参列表){
//方法体
}
修饰符可以省略,也可以public,private,protected,abstract,static,final,其中public,private,protected三个只能选其一,abstract,final只能选其一,它们与static组合使用.
返回值类型可以是void无返回值,也可以是Java允许的任意数据类型,定义了除void之外的任意类型,则方法必须有return语句.
方法名任意合法字符即可
形参列表可以有零个或多个
static是个特殊的修饰符,可以用来修饰属性,方法,内部类,初始化块等.被static修饰的属性,方法都属于类的属性,方法,而不属于类的实例的.因此被static修饰的方法,属性,也被称为类方法,类属性,而没被static修饰的称为实例方法,实例属性.由于static英文翻译是"静态",类方法,类属性也称为静态方法,静态属性,实例属性,实例方法也称为非静态属性,非静态方法.
4. 构造器:
[修饰符] 构造器名(形参列表){
//构造器执行体
}
修饰符可以是public,private,protected其中之一.
构造器名必须和类名相同.
形参列表可以有零个或多个
构造器是特殊的方法,但是构造器不能定义返回值类型,如果定义了返回值类型,Java会把构造器当作方法处理.若类里没有构造器,系统会默认为该类提供一个无参的构造器.构造器只会执行一次,类初始化时调用,而方法可以执行多次,是在对象创建后,需要时才会调用.
5. 对象:
@Data
public class User {
private String name;
private Integer age;
public static Double height;
public void test(){
System.out.println("abc");
}
public static void testStatic(){
System.out.println("static");
}
}
class Test {
public static void main(String[] args) {
//通过new关键字调用User类的无参构造器创建实例,创建对象的根本途径是构造器
User user = new User();
//User的属性通过实例调用
user.setName("张三");
user.setAge(30);
//User的类属性通过类.属性调用
User.height = 175.3;
//通过实例调用实例方法
user.test();
//通过类调用类方法
User.testStatic();
System.out.println(User.height);
System.out.println(user);
}
}
static修饰的方法和属性可以用类.属性/方法调用,也可以用实例调用,但是不推荐用实例对象调用,没有用static修饰的方法只能用实例对象调用.
User user = new User(); 创建了一个User实例,也就是User对象.并把User对象赋值给变量user.从User类的定义来看,它具有多个属性,在内存中也就需要多块内存来存储不同的属性,当把User对象赋值给引用变量user的时候,变量user存储的是指向User对象的内存地址,
2. 方法
方法是类或对象的行为特征的抽象.方法不可单独存在,必须定义在类里.
1.方法所属性:
方法不能独立定义,只能定义在类里
从逻辑意义上讲,方法要么属于一个类,要么属于一个对象
方法不能独立执行,方法执行必须是类或者对象作为调用者
2. 方法参数传递:
public static void main(String[] args) {
way("aaa","bbb");
}
public static void way(String desc,String des){
//把desc的值赋值给a
String a = desc;
//des的值赋值给desc
desc = des;
//a的值赋值给des
des = a;
System.out.println("desc值:" + desc + " des值: " + des);
}
运行结果:
desc值:bbb des值: aaa
way()方法定义两个形参,字符串desc和des,由main方法中调用way()方法时队形参进行赋值.
3. 方法形参长度可变:
jdk1.5之后,Java支持定义形参长度可变的参数,从而允许方法指定数量不确定的形参.方法如下:
public static void main(String[] args) {
variable(2,"a","b","c");
String[] strings = {"d","e","f"};
variable(1,strings);
}
public static void variable(Integer a,String ... str){
//把str当作数组类型处理
for (String s : str){
System.out.println(s);
}
System.out.println(a);
}
运行结果:
a
b
c
2
d
e
f
1
长度可变的形参只能放在形参列表的最后,也就是说一个方法只能有一个长度可变的形参.这个长度可变的形参既可以传入多个参数,也可以传入一个数组.
4. 递归方法:
一个方法体内调用自身,就是递归.
public static void main(String[] args) {
System.out.println(recursion(3));
}
public static Integer recursion(Integer a){
if (a == 0){
return a;
}else {
return recursion(a -1);
}
}
运行结果:
0
main方法中调用recursion(Integer a)方法,a的值为3.在recursion(Integer a)的方法中,当a==0时返回a,不等0时,调用它自己并且把a-1.这个方法时可以计算的,若是a+1那么a永远不会等于0,程序就会无穷递归,也就是陷入死循环.因此,递归一定要向已知方向递归.
5. 方法重载:
Java允许同一个方法中存在相同方法名的方法,只要参数列表,参数类型不同即可.
public static void main(String[] args) {
overload();
System.out.println(overload("a"));
System.out.println(overload(3));
}
public static void overload() {
System.out.println("无形参");
}
public static String overload(String a) {
return "形参:" + a;
}
public static String overload(Integer b) {
return "形参:" + b;
}
运行结果:
无形参
形参:a
形参:3
6. 成员变量和局部变量:
根据定义变量的位置不同,可以分为两大类,成员变量和局部变量.成员变量定义在类里,也就是属性,局部变量定义在方法中.
成员变量分为实例变量和类变量,使用static定义的成员变量是类变量,不使用static定义的成员变量是实例变量.实例变量从当前类的实例被创建开始存在,当前实例对象消失而消失,类变量从类的准备阶段开始存在,类销毁而销毁.
局部变量根据定义形式的不同,分为形参,方法局部变量,代码块局部变量.局部变量除了形参之外,其他两种必须显式的初始化,否则不可被调用.
7. 局部变量初始化:
局部变量定义后必须经过初始化才能使用,与成员变量不同,局部变量不属于任何类或者实例对象,它保存在所属方法的栈内存中.栈内存中的变量不需要系统垃圾回收,因为栈内存中的变量是随着方法或代码块的运行结束而结束的.
3. 封装
面向对象有三大特征,封装,继承,多态. 封装是指隐藏对象的属性和实现细节,仅对外提供公共访问方式.隐藏和提供访问都需要通过Java提供的访问控制符来实现.
1. 访问控制符:
Java提供了三个访问控制符,private,protected,public,提供了四种访问级别,除了public,protected,private三种访问级别外,还有一种是不加任何访问控制符的default访问级别.
访问控制级别由小到大排序如下:
private ---> default ---> protected ---> public
范围 | private | default | protected | public |
---|---|---|---|---|
同一类中 | √ | √ | √ | √ |
同一包中 | √ | √ | √ | |
子类中 | √ | √ | ||
全局范围内 | √ |
2. import和package:
在访问修饰符的控制级别提到了包,定义包用package关键字.包的作用就是对类文件进行分类管理和给类文件提供多层名称空间.
import是导入,使用import关键字导入指定包中的类,如果导入的两个包中存在着相同名称的类。这时如果用到该类,必须在代码中指定包名.
4. 继承
继承是面向对象的三大特征之一.继承提高了代码的复用性,也为另一个特征多态提供了前提.Java值支持单继承,不支持多继承,但是支持多重继承.
1. 特点:
继承通过extends关键字实现,实现继承的类被称为子类,被继承的类被称为父类.
示例如下:
public class Parent {
public String name;
public void desc(){
System.out.println("name: "+name);
}
}
public class Child extends Parent{
public static void main(String[] args) {
Child child = new Child();
child.name = "张三";
child.desc();
}
}
执行结果:
name: 张三
由程序可以看出,Child类是个空类,只有main方法,但是实例化child对象之后,可以访问name属性和desc()方法.这就是继承的作用,子类继承父类的属性和方法.
2. 覆盖(重写override):
public class ChildTwo extends Parent{
@Override
public void desc() {
System.out.println("重写父类方法.......");
}
public static void main(String[] args) {
ChildTwo childTwo = new ChildTwo();
childTwo.name = "李四";
childTwo.desc();
}
}
执行结果:
重写父类方法.......
这种子类包含父类同名方法的现象叫做方法重写,也就是方法覆盖.方法的重写要遵循"两同两小一大"的原则.两同是方法名,形参列表必须相同,子类的方法返回值类型和异常定义要比父类的返回值类型和异常更小或者相等.一大就是子类的访问权限要比父类更大或者相等.
如果要在子类中调用父类的方法,需要用super关键字.
public class ChildTwo extends Parent{
@Override
public void desc() {
System.out.println("重写父类方法.......");
}
public static void main(String[] args) {
ChildTwo childTwo = new ChildTwo();
childTwo.name = "李四";
childTwo.desc();
childTwo.test();
}
public void test(){
//调用父类方法
super.desc();
}
运行结果:
重写父类方法.......
name: 李四
super是Java提供的一个关键字,它是直接父类对象的默认引用.正如this一样,super也不能出现在static方法中.static的方法是属于类的,该方法的调用者可能是一个类,而不是一个对象,也就没有父对象了,super也就失去引用的意义了.
重载和重写,重载发生在同一类的多个同名方法之间,而重写是发生在子类和父类的同名方法之间.
5. 多态
多态是指同一事物的不同表现.体现在父类引用或者接口引用指向了自己的子类对象.
public class Parent {
public String name = "张三";
public void desc(){
System.out.println("父类被重写方法....");
}
public void one(){
System.out.println("父类普通方法....");
}
}
public class ChildThree extends Parent{
private Integer name = 13;
@Override
public void desc() {
System.out.println("子类重写父类方法....");
}
public void two(){
System.out.println("子类普通方法....");
}
public static void main(String[] args) {
Parent parent = new Parent();
//输出张三
System.out.println(parent.name);
//输出父类被重写方法....
parent.desc();
//输出父类普通方法....
parent.one();
ChildThree childThree = new ChildThree();
//输出13
System.out.println(childThree.name);
//输出父类普通方法....
childThree.one();
//输出子类重写父类方法....
childThree.desc();
Parent parent1 = new ChildThree();
//输出张三,表示访问的是父类属性
System.out.println(parent1.name);
//输出父类普通方法....
parent1.one();
//输出子类重写父类方法....
parent1.desc();
//parent1.two()无法通过编译,以为编译时parent1的类型是Parent,而Parent中没有two()方法
//parent1.two();
}
}
输出结果:
张三
父类被重写方法....
父类普通方法....
13
父类普通方法....
子类重写父类方法....
张三
父类普通方法....
子类重写父类方法....
Java引用类型有两个类型,一个是编译时的类型,一个是运行时的类型,编译时的类型由声明该变量时的类型决定,运行时类型由实际赋值给该变量的类型决定.如果编译时类型和运行时类型不一致,就会出现多态.
上篇到这里结束,若有错误和补充欢迎指出