面向对象三大特性:封装、继承、多态。
1.封装
将一系列相关事物的共同的属性和行为提取出来,放到一个类中,同时隐藏对象的属性和实现细节,仅对外提供公共的访问方式。
【JavaBean类就可以看作是封装的完美案例。】
setter和getter
其实指的分别是setXxx和getXxx两个函数。setXxx可以修改对应属性的值,而getXxx则可以获取对应属性的值。
他俩能给private属性赋值个取值。
this
每一个创建的对象都有一个this属性,指向该对象本身(类似于指针,但在Java中叫做引用)。
1.用法:
①this.属性名; (可调用当前对象的属性,this.属性名就是当前对象的属性)
②this.方法名(参数); (可调用当前对象的方法)
③知识延申 :
PS : this(参数列表) 可以访问本类的构造器。但要注意:Δ此时this后不需要加"."。Δ该途径只能在构造器中使用,且使用时必须置于构造器的首句。我们称之为“构造器的复用”。
可以解决形参名与属性名的重名问题。
package knowledge.define;
public class Phone {
//成员变量:
private int age;
//this 关键字对于属性的应用:
public void pintAge () {
int age = 10;
System.out.println("1:" + age);
System.out.println("2:" + this.age);
}
}
public class
TestPhone {
public static void main(String[] args) {
//1.创建对象
Phone p = new Phone();
//2.调用成员方法
p.pintAge();
}
}
1:10
2:0
因为this.age没有setAge赋值,整型默认值为0
构造器
构造器,也叫构造方法,指用来帮助创建对象的方法,但仅是帮助。它不是用来创建新对象的,而是完成对新对象的初始化。
实际上是:new关键字来创建对象,并在堆内存中开辟空间,然后使用构造器完成对象的初始化。
1.构造器需要满足的要求:
构造方法名必须与类名相同!(包括大小写)
构造方法没有返回值!(但是也可以在方法内部写一个return)
2.当类中没有定义任何构造器时,该类默认隐含一个无参构造。这也是为什么我们之前写过的类中没有定义构造器,却依然可以创建该类的对象,因为系统默认给出了无参构造,所以就会以默认的无参构造对新对象进行初始化
3.构造器可以重载,就和方法一样,同一个类中可以定义多个构造器。
4.构造器是在执行new关键字的时候,由系统来完成的,即在创建对象时,系统会自动匹配并调用该类的某个构造器完成对对象的初始化。
构造器示例:
public class Phone {
private int age = 11;
//公有的空参构造 (重点)
public Phone() {
System.out.println("这是空参构造,成功调用此构造时打印这句话");
}
public Phone(int age) {
System.out.println("这句话打印出来,说明带参构造被成功调用");
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class TestKunKun {
public static void main(String[] args) {
//调用有参构造
Phone phone1 = new Phone(18);
//调用无参构造
Phone phone2 = new Phone();
}
}
2.继承
Java中继承的特点:
1.仅支持单继承。每个类最多有且只能继承一个类,不能同时继承多个类。但是,Java支持多层继承。 多层继承指当父类衍生出一个子类后,该子类可以作为父类继续衍生出它的子类.
2.父类私有成员子类无法继承。发生继承关系后,子类拥有了父类的非私有成员。
3.父类构造器子类不能继承。构造器用于初始化对象。父类构造器用于初始化父类对象,子类构造器用于初始化子类对象。
super关键字
1.类似于this关键字,super关键字也是一个指针,当然了,在Java中叫做引用。
this是一个指向当前对象的引用。而super则是指向当前对象父类的引用(即父类内容内存空间的标识)。
当new关键字创建子类对象时,子类对象的堆空间中会有一部分用于存放父类的内容,即继承自父类的非私有成员。super就指向这么一部分。可以理解为,super指向的部分是在this指向的部分的范围内。在使用时,this从本类开始找,super从父类开始找。
2.直接访问父类变量的方式 : super.父类变量名 (仅能访问非私有属性,所以是直接访问)
3. new关键字创建对象后,对象初始化顺序:
先初始化父类内容,再初始化子类内容。(原因是创建子类对象时,优先调用父类的构造器
4.java中查找变量的顺序:
5. this关键字解决了局部变量和本类成员变量的命名冲突问题。this关键字使得我们可以在局部变量存在的情况下,避开Java就近原则的约束,在局部位置使用成员变量。
super关键字,就是从父类开始找,在局部位置使用父类成员变量。
继承关系中构造器的使用
继承设计中的基本思想 : 父类的构造器初始化父类内容,子类的构造器初始化子类内容。
(1)创建子类对象时,优先调用父类的构造器。
(2)子类构造器的第一行,默认隐含语句super(); 用于调用父类的默认无参构造。
(3)当父类有参无参都有,子类构造器的使用情况 : 无参对无参,有参对有参。即,在子类无参构造中通过“super();” 调用父类的无参构造;在子类有参构造中通过“super(参数);” 调用父类的有参构造。
方法重写
重写必须满足返回值类型、方法名,参数列表都相同!即——外壳不变,内部重写。
可以用@Override注解来标注。
①父类私有方法不能被重写。
②子类方法访问权限不能小于父类方法,即访问权限 : 子类 ≥ 父类。(本文后面我们就会讲到Java四大访问修饰符)
③子类不能比父类抛出更大的异常
方法重写和方法重载的区别 :
重载:是指不同的函数使用相同的函数名,但是函数的参数个数或类型不同。调用的时候根据函数的参数来区别不同的函数。重载是在一个类中。
重写:是指在派生类中重新对基类中的虚函数(注意是虚函数)重新实现。即函数名和参数都一样,只是函数的实现体不一样。重写是子类与父类之间。
Java四大访问权限修饰符 :
访问权限修饰符指的是用来修饰成员变量,成员方法和类,来确定它们的访问权限的。
分别是private、默认、protected,public。
private修饰的成员只能在本类使用。
public修饰的成员可以被所有类使用。
默认修饰符,指的就是没写修饰符。默认修饰符修饰的成员允许在当前所在包下其他类使用。
protected修饰符修饰的成员除了可以在本包下使用,在其子类中也可以使用。
四大修饰符按照根据访问权限从小到大的原则依次是 : private < 默认 < protected < public。
延申(关于类和源文件的关系) :
①一个Java源文件中可以定义多个类,源文件的基本组成部分是类。
②源文件中定义的类,最多只能有一个类被public修饰,其他类的个数不限。
③如果源文件中有被public修饰的类,那么源文件名必须与该类类名保持一致。
④如果源文件中没有被public修饰的类,那么源文件名只要符合命名规范就可以。
⑤main函数不一定非得写在public修饰的类中,也可以将main函数写在非public修饰的类中,然后通过指定运行非public类,这样入口方法就是非public类的main方法。
————————————————
部分内容摘自:https://blog.csdn.net/TYRA9/article/details/128523078
3.多态
多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生不同的状态。
条件
在Java中要实现多态,必须要满足如下几个条件,缺一不可:
1.必须在继承体系下
2.子类必须要对父类方法进行重写
3.通过父类的引用调用重写的方法
向上转型和向下转型
向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。
语法格式:父类类型 对象名 = new 子类类型()
(1)直接赋值
Parent c = new Child();
(2)方法的参数,传参的时候进行向上转型
public static void fun(Parent p)
{
//...
}
(3)返回值转型
public static Child fun1()
{
Child c = new Child();
return c;
}
向下转型:将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换。
注:向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为true,则可以安全转换。
重写
外壳不变,核心重写! 重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
方法重写的规则:
1.返回值类型,方法名 ,参数列表 必须是一样的(返回值是父子关系,可以构成重写叫协变)
2.被重写的方法的访问修饰限定符在子类中要大于父类的
3.被private修饰的方法是不可以被重写的
4.被static修饰的方法是不可以被重写的
5.被final修饰的方法是不可以被重写的
6.构造方法不能被重写的
final关键字
final:最终的、不可改变的。可用于修饰类、方法、变量。
类:被修饰的类,不能被继承
方法:被修饰的方法,不能被重写
变量:被修饰的变量,有且只能被赋值一次
public final class String 、public final class Math 、public final class Scanner 等
,很多我们学习过的类,都是被final修饰的,目的就是供我们使用,而不让我们所以改变其内容。
1.修饰变量-成员变量
成员变量如果被final修饰,一旦有了初始值 就不能被重新赋值。
由于成员变量具有默认值,用final关键字修饰后 不会再给默认值,必须手动赋值,否则会报错。
因此必须手动初始化,有两种初始化方式——显示初始化和构造方法初始化。
(1)直接赋值
public class Person {
private final String name = "Jenny";
}
(2)构造方法赋值
public class Person {
//对于final类型的成员变量,有两种初始化方式(赋值方式),显示初始化和构造方法初始化,只能选其中一个
// 定义成员变量时指定默认值,合法。
final String name = "Jenny";
final int num;
public Person() {
// 在构造器中分配初始值
num = 20;
}
public Person(int num) {
// 在构造器中分配初始值
this.num = num;
}
}
static关键字
static是静态的意思,可用来修饰 成员方法、成员变量。static修饰后的变量、方法,可以被类的所有对象共享
static修饰成员变量之后,这个变量被称为类变量或静态成员变量;无static修饰的成员变量是属于每个对象的,这个变量被称为实例变量
static修饰方法之后,这个方法被称为类方法或静态方法;无static修饰的成员方法是属于每个对象的,这个成员方法也叫做实例方法
推荐以 对象.静态成员变量
,类名.静态方法
的形式来访问
public class Employee {
//静态成员变量,属于类,只有一份
public static String companyName = "abc";
public static void work() {
System.out.println("我们都在" + companyName + "公司工作");
}
//实例变量
private String name;
private Integer age;
public void achive() {
System.out.println(name + "实现大成就");
}
}
public static void main(String[] args) {
System.out.println(Employee.companyName); //abc
Employee.companyName = "learn"; //直接用类来访问
System.out.println(Employee.companyName); //learn
Employee.work(); //直接用类来访问
Employee employee1 = new Employee("zhangsan", 18);//实例化对象来访问
System.out.println(employee1.getAge()); //18
employee1.achive();//对象来访问
}
注:
(1)静态方法只能访问静态成员。不能直接访问实例成员
若想要使用静态方法调用非静态方法,只需要实例化new一个类对象,此时jvm虚拟机就会为对象开辟一块内存,该类的所有方法也随之被存储到内存当中。此时静态方法和非静态方法都在内存当中,所以在静态方法中可以使用对象去调用一个非静态方法。
(2)实例方法可以访问静态成员,也可以访问实例成员
(3)静态方法中是不可以出现this关键字的。this指当前对象,静态方法中不用声明实例对象
在java中,程序执行时 类的字节码文件会被加载到内存中,如果类没有创建对象 类的成员变量则不会分配到内存;
但对于被static修饰的静态变量/方法,堆中有一个专属的静态变量区,当JVM虚拟机将字节码加载到内存时,会为静态变量/方法在堆中分配出一段空间用于放置值,即静态变量/方法跟随类加载而加载
抽象类
1.抽象类概念
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
我们可以把它设计成一个 抽象方法(abstractmethod), 包含抽象方法的类我们称为 抽象类(abstract class)
2.抽象类语法
在Java中,一个类如果被 abstract 修饰称为抽象类,抽象类中被 abstract 修饰的方法称为抽象方法,抽象方法不用给出具体的实现体。
abstract class A{
abstract void fun();
}
class B extends A{
void fun()
{
System.out.println("B fun");
}
注意:抽象类也是类,内部可以包含普通方法和属性,甚至构造方法
3.抽象类特性
1.使用abstract修饰的方法称为抽象方法
2.使用abstract修饰的类称为抽象类
3.抽象类是不可以实例化的
4.抽象类当中可以和普通类一样定义成员变量和成员方法
5.当一个普通的类继承这个抽象类,那么需要重这个抽象类当中的所有的抽象方法!!!
6.抽象类的出现就是为了被继承!!!
7.abstract 和final不能共存
8.被private static 修饰的抽象方法也是不可以的
接口
接口
1.接口的概念
接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。
2.语法规则
接口的定义格式与定义类的格式基本相同,将class关键字换成interface关键字,就定义了一个接口。
public interface 接口名称{
// 抽象方法
public abstract void method1(); // public abstract 是固定搭配,可以不写
public void method2();
abstract void method3();
void method4();
// 注意:在接口中上述写法都是抽象方法,跟推荐method4,代码更简洁
}
3.接口使用
接口不能直接使用,必须要有一个"实现类"来"实现"该接口,实现接口中的所有抽象方法。
public class 类名称 implements 接口名称{
// ...
}
// USB接口
public interface USB {
void openDevice();
void closeDevice();
}
// 鼠标类,实现USB接口
public class Mouse implements USB {//实现接口
@Override
public void openDevice() {//实现方法
System.out.println("打开鼠标");
}
@Override
public void closeDevice() {
System.out.println("关闭鼠标");
}
public void click(){
System.out.println("鼠标点击");
}
}
4.接口特性
(1).接口当中不能有被实现的方法,意味着只能有抽象方法。两个方法除外:一个是static修饰的方法一个是被default修饰的方法.
(2).接口当中的抽象方法,默认都是public abstract修饰的
(3).接口当中的成员变量,默认都是public static final修饰的
(4).接口不能进行实例化
原文链接:https://blog.csdn.net/weixin_66484088/article/details/135323441
5. 在Java中,类和类之间是单继承的,但是一个类可以实现多个接口。接口与接口之间可以多继承。
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
// 两栖的动物, 既能跑, 也能游
interface IAmphibious extends IRunning, ISwimming {
}
class Frog implements IAmphibious {
...
}
6.抽象类和接口的区别
抽象类和接口都是 Java 中多态的常见使用方式. 都需要重点掌握. 同时又要认清两者的区别(重要!!! 常见面试题).
核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写),
而接口中不能包含普通方法, 子类必须重写所有的抽象方法.
7.Object类
Object是默认类,除Object类外所有的类都有继承关系,默认继承Object类。所以可以直接使用Object的方法(当然有些需要重写方法)。
比如使用Object类中的equals
对象比较equals方法
a.如果左右两侧是基本类型变量,比较的是变量中值是否相同
b.如果左右两侧是引用类型变量,比较的是引用变量地址是否相同
c.如果要比较对象中内容,必须重写Object中的equals方法,因为equals方法默认也是按照地址比较的:
class Preson{ // 默认继承Object类
String name;
int age;
public Preson(String name, int age) {
this.name = name;
this.age = age;
}
}
public static void main(String[] args) {
Preson a = new Preson("张三",18);
Preson b = new Preson("张三",18);
System.out.println(a.equals(b));
}
没有重写就是两个类对象比较地址是否相同,为False
重写:后就是True
@Override
public boolean equals(Object obj) {
Preson b = (Preson) obj;
return this.age==b.age&&this.name.equals(b.name);
}