什么是面向对象
面向对象是解决复杂问题的,通过面向对象的方式便于我们从宏观上把握事物之间复杂的关系,方便我们分析整个体系,具体到微观操作需要使用面向过程方式来处理
类与对象的概念
对象:是具体的事物
类:是对对象的抽象(抽象□抽出象的部分)
先有具体的对象,然后抽象各个对象的之间的部分,归纳出类通过类在认识其他对象。
对象和类的关系
1、特殊到一般,具体到对象。
2、类可以看成一类对象的模板,对象可以看成该类的一个具体实例。
3、类是用于描述同一类形的对象的一个抽象的概念,类中定义了这一类对象所应具有的静态的动态属性。
4、JDK提供了很多类供编程人员使用,编程人员也可以定义自己的类。
自定义类的组成
1、属性
性用于定义该类或该类对象包含的数据或者说静态特征。属性作用范围是整个类体。
在定义成员变量时可以对其初始化,如果不对其初始化,Java使用默认的值对其初始化。
I、属性定义格式
[修饰符]属性类型 属性名 = [默认值];
II、修饰符(可以省略不写)
修饰符 | 作用 |
---|---|
public | 公共修饰符 |
protected | 访问修饰符 |
private | 私有修饰符 |
Static | 静态修饰符 |
final | 常量修饰符 |
在类中,用static声明的成员变量为静态成员变量 ,或者叫做: 类属性,类变量.
- 它为该类的公用变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化,
- 对于该类的所有对象来说,static成员变量只有一份。被该类的所有对象共享!!
- 可以使用”对象.类属性”来调用。不过,一般都是用“类名.类属性”
- static变量置于方法区中!
用static声明的方法为静态方法
- 不需要对象,就可以调用(类名.方法名)
- 在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可直接访问非static的成员。
- 但是可以通过对象使用。
- 静态方法不能以任何方式引用this和super关键字
III、属性类型
可以是任何类型,基本数据类型和引用数据类型
V、属性名
合法标识符即可。首字母小写,驼峰原则
2、构造器
I、什么是构造器:是为成员变量初始化信息的。
II、声明格式:
[修饰符] 类名(形参列表){
//n条语句
}
构造器要求:
1、构造器的方法名称和类名同名一致。
2、构造器虽然有返回值,但是不能定义返回类型(返回值得类型肯定是本类),不能在构造器里调用return。
3、调用的时候需要通过new关键词来调用。
4、每个类默认都存在一个空参数的构造器,不写也能直接使用。方便的当前类能够实例化对象;如果已定义则编译器不会添加无参构造方法!
5、构造器是支持重载的调用的时候可以通过重载方法来给对象的某些属性进行赋值动作。
6、如果在类中定义了其他构造器之后,默认的空构造器就不存在了
7、修饰符final abstract static不能用来修饰构造器
3、方法
定义格式:
[修饰符] 方法返回值类型 方法名(形参列表) {
// n条语句
}
成员变量与局部变量的区别
- 声明位置不同
– 成员变量 : 类中方法外
– 局部变量 : 方法中(块中)- 作用范围不同
– 成员变量 : 当前类中
– 局部变量 : 当前方法
== 不同的方法中即使有同名的局部变量,没有关系,互不影响,建议相同- 内存存放的位置的
– 成员变量 : 堆内存中
– 局部变量 : 栈内存中- 默认值情况不同
– 成员变量 : 有默认值
– 局部变量 : 没有默认值
重载
- 方法重载: 两同三不同 同一个类方法名相同,形参类型 个数 顺序不同
- 构造器重载: 只看形参即可 形参类型 个数 顺序不同。调用时按“就近最优原则”
class Dog{
String color;
String name;
//空构造
Dog(){}
public Dog(String name,String color){
this.name=name;
this.color=color;
}
public static void main(String[ ] args) {
Dog d1 = new Dog();
Dog d2 = new Dog("二狗子", "白色");
Dog d3 = new Dog("三狗子", "土色");
}
}
this关键字
this 即”自己”,代表对象本身,谁调用代表谁。在成员方法中或构造器中隐式的传递。作用如下:
- this.属性避免属性和形参、局部变量同名,发生就近原则
- this([实参列表]): 构造器的首行调用其他构造器。
class Web{
//网址
public String url;
public Web(){
System.out.println("构造器");
}
public Web(String url){
this(); //this()构造器的调用
this.url =url;//this.属性 区分同名问题
}
//赋值
public void setUrl(String url){
this.url =url;
}
/**
属性与形参 同名,发生就近原则
public Web(String url){
url =url;
}
//二者不同名
public Web(String u){
url =u;
}*/
}
. 注意: 静态方法中无 this
重写(Override)
为什么要重写:父类的功能不满足子类的要求,所以子类会拓展该功能,这就是重写。
重写的先决条件:
1: 一定要发生继承关系
2: 子类定义了和父类中同名的方法
3: 方法的返回值和参数列表要一样
4:不同的两个类
5:继承关系|实现关系
6:方法签名相同
优势:
避免了子类随意设计自己的功能;
public class OverrideTest {
public static void main(String[] args) {
Sicong sicong=new Sicong();
sicong.getMoney(); //调用子类中重写方法
}
}
//父类
class Jianlin{
public void getMoney(){
System.out.println("先定一个小目标,赚他个一个亿");
}
}
//子类
class Sicong extends Jianlin{
@Override //强制检查是否为重写方法
public void getMoney(){
super.getMoney();//在父类的原赚钱方法上扩展新功能,老功能不变
System.out.println("我认识的人都没我有钱");
}
}
以下修饰符、修饰的内容不能重写:
- private修饰的方法不能被重写
- final修饰的方法不能被重写
- static修饰的方法不能被重写(子类如果出现和父类静态方法同名情况,那么子类中的方法也必须为静
态的)
类与类之间的关系
在设计模式中类与类之间的关系主要有6种:依赖、关联、聚合、组合、继承,实现, 它们之间的耦合
度依次增加。
继承关系
继承指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加
它自己的新功能的能力。在Java中继承关系通过关键字extends明确标识。
public class Person {
String name;
int age;
void move(){}
}
//继承
class Student extends Person{
void study(){}
}
class Teacher extends Person{
void teach(){}
}
优点:
1、通过继承可以简化类的定义,实现代码的重用|提高代码复用性
2、可以更好的扩展程序
3、子类一旦继承父类,可以有权使用父类中的成员,也可以扩展定义子类独有内容
4、java是单继承继承,实现简单
缺点:
1、子类与父类之间紧密耦合(耦合度高),子类依赖于父类的实现,子类缺乏独立性。
2、不便于后期维护
3、单继承一个子类只能有一个父类,不够灵活,不便于后期维护
依赖关系
简单的理解,依赖就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、临时性的、非
常弱的,但是类B的变化会影响到类A。比如某人要过河,需要借用一条船,此时人与船之间的关系就是
依赖。表现在代码层面,为类B作为参数被类A在某个method方法中使用。
public class Person {
public void drive(Car car){} //方法参数
}
class car{}
关联关系
关联体现的是两个类之间语义级别的一种强依赖关系,比如我和我的朋友,这种关系比依赖更强、不存
在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。关联可
以是单向、双向的。表现在代码层面,为被关联类B以类的属性形式出现在关联类A中,也可能是关联类
A引用了一个类型为被关联类B的全局变量。
public class Person {
public Address address; //关联关系
public void setAddress (Address address){
this.address= address;
}
public Address getAddress (){
return address;
}
}
class Address{}
聚合关系
单向,关联关系的一种,与关联关系之间的区别是语义上的,关联的两个对象通常是平等的,聚合则一
般不平等,有一种整体和局部的感觉,实现上区别不大。表现在代码层面,和关联关系是一致的,只能
从语义级别来区分。
public class Team {
public Person person;
public Team(Person person){
this.person = person;
}
}
组合关系
单向,是一种强依赖的特殊聚合关系
public class Person {
public Head head;
public Body body;
public Person(){
head = new Head();
body = new Body();
}
}
实现关系
实现指的是一个class类实现interface接口(可以是多个)的功能,实现是类与接口之间最常见的关系。
在Java中此类关系通过关键字implements明确标识。
interface Vehicle{
void move();
}
class Ship implements Vehicle{
void move(){
System.out.println("水里移动..");
}
}
class Car implements Vehicle{
void move(){
System.out.println("陆地跑..");
}
}
多态
多态定义及用法
1、什么是多态
1、一种事物的多种形态|多种表现形式 ==> 行为多态 : 一个方法的不同实现方式
2、父类引用指向子类的对象
2、多态存在的必要条件
- 要有继承,要有方法重写,父类引用指向子类对象
普通调用
- 能够调用本类中定义的成员 + 从父类中继承的成员
标准写法
- 对应类型的数据赋值给对应类型的变量
3、多态调用的特点
1、多态调用成员变量 : 编译运行看父类|左边|类型
2、多态调用成员方法 : 编译看父类|左边|类型,运行看子类|右边|对象
3、多态调用只能调用父类中定义的成员,对子类新增内容不可见,如果子类中存在重写,调用子类中重写的方法
做题的四打原则
- 继承链
- 编译看类型、确定方法,运行找对象
- 就近最优原则
- 父类引用对子类新增方法不可见
public class TestPolym {
public static void main(String[] args) {
//父类引用指向子类对象
Animal animal = new Dog();
System.out.println(animal.age); //属性调用时,仍 然是基类的属性。属性没有多态!
animal.shout(); //行为存在多态
animalCry(new Dog());
//传的具体是哪一个类就调用哪一个类的方法。大大提高了程序的可扩展性。
//如果没有多态,我们这里需要写很多重载的方法。如果增加一种动物,就需要重载一种动物的喊
叫方法。非常麻烦。
//有了多态,只需要增加这个类继承Animal基类就可以了。
animalCry(new Cat());
}
static void animalCry(Animal a){
a.shout();
}
}
class Animal {
int age=10;
public void shout(){
System.out.println("叫了一声!");
}
}
class Dog extends Animal {
int age=28;
public void shout() {
System.out.println("旺旺旺!");
}
public void gnawBone(){
System.out.println("我再啃骨头");
}
}
class Cat extends Animal {
int age=18;
public void shout() {
System.out.println("喵喵喵喵!");
}
}
引用数据的转换
• 子类转换为父类:自动转换
– 引用不能操作子类新增的成员变量和方法。
– 引用可以操作子类继承或重写的成员变量和方法
– 如果子类重写了父类的某个方法,引用调用该方法时,是调用的重写方法。
• 父类转换为子类:强制转换
– 为了调用子类独有的内容
– (绝不是做手术,而是父类引用的真面目就是一个子类对象,否则会出现类型转换错误)
//父类引用指向子类对象->向上转型
Animal animal = new Dog();
animal.shout(); //调用父类中有的成员
//向下转型
Dog dog = (Dog) animal; //编写程序时,如果想调用运行时类型的方法,只能进行类型转换。不然通
不过编译器的检查。
dog.gnawBone(); //调用子类独有成员
编写程序时,如果想调用运行时类型的方法,只能进行类型转换。不然通不过编译器的检查。但是如果
两个没有关联的类进行强制转换,会报: ClassCastException 。 比如:本来是狗,我把它转成猫。就
会报这个异常。
instanceof
在向下转型的时候,为了避免类型转换异常 ClassCastException 的出现,可以使用instanceof进行判
断。
Animal animal = new Dog();
System.out.println(animal instanceof Animal);
System.out.println(animal instanceof Cat);
System.out.println(animal instanceof Dog);
//先判断后转型
if(animal instanceof Dog){
Dog dog = (Dog) animal;
}
接口
I、什么是接口
- 类只能单继承,接口可以多实现
- 接口是一个特殊的抽象
- 接口是一个引用数据类型
- 是功能的集合(抽象方法的集合)
- 降低了耦合度,解耦(降低了紧密度)
- 定义开发规范
II、继承与实现的区别
- 继承父类:子类继承父类,就可以直接使用父类的成员,不满意可以重写
- 实现接口:实现类一旦实现接口,就必须要重写
III、定义
1、jdk1.7及之前
- 公共的静态的常量 public static final,修饰符可以任意省略
- 公共的抽象的方法 public abstract,修饰符可以任意省略
2、jdk1.8及之后
- 静态方法 : 通过接口名.静态方法名(参数),不能通过实现类对象调用
- 默认方法 : 显示的被default关键字修饰的方法
通过接口的实现类对象去调用
public class Test {
public static void main(String[] args) {
Volant volant = new Angel();
volant.fly();
System.out.println(Volant.FLY_HIGHT);
}
}
interface Volant {
int FLY_HIGHT = 100; // 总是:public static final
void fly(); //总是:public abstract void fly2();
}
interface Honest {
void helpOther();
}
class Angel implements Volant, Honest{
public void fly() {
System.out.println("我是天使,飞起来啦!");
}
public void helpOther() {
System.out.println("扶老奶奶过马路!");
}
}
class GoodMan implements Honest {
public void helpOther() {
System.out.println("扶老奶奶过马路!");
}
}
class BirdMan implements Volant {
public void fly() {
System.out.println("我是鸟人,正在飞!");
}
}
class Bird implements Volant {
public void fly() {
System.out.println("正在飞!");
}
}
class Plane implements Volant {
public void fly() {
System.out.println("正在飞!");
}
}
class Satellite implements Volant {
public void fly() {
System.out.println("正在飞!");
}
}
class Missile implements Volant {
public void fly() {
System.out.println("正在飞!");
}
}
注意:
1.接口不能实例化
2.实现类实现接口,通过implements关键字,继承父类通过extends关键字
3.通过实现类对象调用接口中的功能 :
具体实现类 : 重写所有的抽象方法 + 按需新增
抽象实现类 : 按需重写抽象方法 + 按需新增
4.类同时继承父类实现接口时候,需要先继承后实现
5.类与类之间只能继承的,并且单继承机制
接口与接口之间只能继承,可以多继承
类与接口之间只能是类实现接口,可以多实现
内部类
I、成员内部类
当内部类定义在外部类的成员位置
可以被成员修饰符所修饰,可以继承其他父类或实现其他接口
成员内部类中可以定义属性,功能等,不能定义静态的,除了静态常量
成员内部类中可以直接使用外部类的成员,包括私有的
在外部类中需要通过成员内部类的对象方法其成员,包括私有的
其他类中使用成员内部类的成员,需要依赖外部类对象创建内部类对象,通过内部类对象调用其成员
外部类.内部类 引用 = new 外部类().new 内部类();
public class Test {
public static void main(String[] args) {
//第一种方式:
Outter outter = new Outter();
//必须通过Outter对象来创建
Outter.Inner inner1 = outter.new Inner();
//第二种方式:
Outter.Inner inner2 = outter.getInnerInstance();
}
}
class Outter {
private Inner inner = null;
public Outter() {
}
public Inner getInnerInstance() {
if(inner == null)
inner = new Inner();
return inner;
}
class Inner {
public Inner() {
}
}
}
注意:除了静态内部类以外,其他的内部类中不可以定义静态内容,除了静态的常量
II、私有内部类
被private修饰的成员内部类
私有内部类中可以直接访问外部类的成员,包括私有的
在所在外部类中通过对象可以访问私有内部类的成员,包括私有的
其他类中无法访问私有内部类
public class Class003_Outer {
private int i = 1;
private static int j = 2;
//私有内部类
private class Inner{
private int a = 10;
private static final int B = 20;
public void inner(){
System.out.println(i);
System.out.println(j);
}
}
public void outer(){
Inner in = new Inner();
System.out.println(in.a);
}
}
III、静态内部类
被static修饰的成员内部类成为静态内部类
可以定义静态内容,可以定义非静态成员
在静态内部类的静态方法中,可以直接使用静态内容,需要通过对象访问成员,包括私有的
在静态内部类的成员方法中,可以直接使用内部类的成员,可以直接使用外部类的静态内容,需要通过外部类的对象访问外部类的成员,包括私有的
其他类中可通过new 外部类的类名.静态内部类(),通过内部类对象方法其成员,通过外部类.内部类的类名访问其静态内容
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
}
}
class Outter {
public Outter() {
}
static class Inner {
public Inner() {
}
}
}
V、局部内部类
定义在外部类的局部位置
局部内部类中不能定义静态内容除了静态的常量
局部内部类中可以直接使用外部类的成员包括私有的
局部内部类中要使用所在方法的局部变量(参数),要求这个局部变量被final修饰为常量
在jdk1.8版本开始,如果在局部内部类中使用了所在方法的局部变量,这个局部变量会默认被final修饰
所在方法中通过局部内部类的对象访问其成员 在其他类中,
在外部类中都无法使用局部内部类
void test(){
int a = 10;
class Inner{
void test(){
System.out.println(a);
}
}
Inner inner = new Inner();
inner.test();
}
IV、匿名内部类
简化 : 1)没有自己类本身作用的,只是为了实现接口|继承抽象类,重写抽象方法的这种实现类|子类,
2)并且只在当前位置使用,满足这样条件的实现类或者子类通过匿名内部类简化
匿名内部类格式 | 匿名内部类对象格式 : 把定义实现类,创建实现类对象合并成为一步实现
new 接口|抽象类(){ ->实现类的类体|子类的类体
//重写抽象方法
};
public class Class006_Outer {
public static void main(String[] args) {
//匿名对象 : 只能在当前行使用一次
System.out.println(new String("abc").length());;
//2)定义实现类对象
Demo demo = new Demo();
//3)调用重写后的方法
demo.swimming();
//匿名内部类使用
//1) 匿名对象 : 因为没有引用指向这个对象
new Swim(){
@Override
public void swimming() {
System.out.println("花样游泳...");
}
}.swimming();
//2)接口多态 : 存在引用指向匿名内部类对象,根据引用多次使用
Swim s = new Swim(){
@Override
public void swimming() {
System.out.println("蛙泳....");
}
};
s.swimming();
s.swimming();
//3)作为方法的实参
test(new Swim() {
@Override
public void swimming() {
System.out.println("蝶泳...");
}
});
}
//参数为所有会游泳的
static void test(Swim swim){
swim.swimming();
}
}
//接口
interface Swim{
void swimming();
}
//1) 定义实现类,重写方法
class Demo implements Swim{
@Override
public void swimming() {
System.out.println("边游泳边喝水...");
}
}
注意 : 通过匿名内部类定义的实现类或子类只能在当前使用一次,因为没有类名无法根据类名继续使用