面向对象
oop object-oriented programming
- 面向对象是把整个需求按照特点、功能划分,将这些存在共性的部分封装成类(类实例化后才是对象),创建了对象不是为了完成某一个步骤,而是描述某个事物在解决问题的步骤中的行为
类 是一类事物的概念(抽象,没有具体化)
对象 类的具体化。
万物皆对象
生活中,歌星是个类,张学友是个歌星
工厂里面:设计图纸就是类,生产的产品是具体的对象
类的五大成员:
-
构造器
-
属性:字段,属性,英文单词:field,字段或者域
-
方法
-
代码块
-
内部类
构造器
java程序没有构造构造器的话都是默认有无参构造器的
类的五大成员之一
语法: public 类名(){} 没有用void或其它的返回类型
作用:1创建对象
2初始化参数
特点:
每个类都会有构造器
如果没有显式的提供无参构造器,系统会提供一个
如果提供了有参构造器,系统不会提供无参构造器
代码示例:
//构造器 public User() { System.out.println("无参构造器-------"); } //有参构造器 public User(int a) { System.out.println("这是有参构造器------"); age = a; } //有参构造器 public User(int a,String s) { age = a; sex = s; }
面向对象特征
- 封装
- 继承
- 多态
关键字:this,super,extends,interface,import…
修饰符:public/protected/default/private
访问权限
关键字 类权限 包权限 包和子类权限 公共权限 场景 private √ × × × 封装 default √ √ × × 在同一个包 protected √ √ √ 主要给子类 public √ √ √ √ 一般作为工具类字段或方法或构造器
分成员变量和局部变量:
成员变量:
写在类里面,方法外面的就是成员变量
局部变量:
方法里面,形参列表里面,构造器里面,代码块里面所定义的变量就是局部变量
两者间的区别:
相同点:要先声明,再使用
不同点:是作用域不同,成员变量在整个类里面都能使用,局部变量只能在方法或构造器或代码块内部所使用
成员变量可以使用 public/protected/private/default,但局部变量只能使用final修饰
生存期不一样,成员变量是属于对象(对象不死,成员变量就不死)的,局部变量是临时的,调用完这个方法(代码块,构造器)后,这个变量就被回收了
方法: 语法:[修饰符]<返回类型> <方法名([形参列表])>{}
方法是一个行为,操作,动作,能干什么,是属于类的成员
取名:与动作单词连用 getUserById(int id):根据id查找用户
findUsers():查找所有用户
方法里面是否要有形参列表取决于具体需求:按照需求(有)(无)可(有)(无)
如果有返回值的:要用return关键字
返回类型分有返回值和无返回值:
无返回值:使用void关键字
有返回值:用int/byte/short/char/long/float/double/String/boolean…
方法重载
定义:同一个类,同一个方法名称,形参列表不同
方法的重载:
两同:同一个类,同一个方法名称
一不同:形参列表不同
顺序不同,个数不同,类型不同
同名不同参,返回值无关
为什么要重载?因为同名的方法不满足需求了
重写:标志 @Override(重写发生在继承里面,重载发生在类里面)
// 要重写toString方法,要不然对象数组输不出对象里的属性,重写返回什么属性就显示什么属性,继承的属性可以在子类一同写父类要显示的属性
@Override
public String toString() {
return "Communist [job=" + job + ", num=" + num + "sex=" + sex + ", age=" + age + ", name=" + name + "]";
}
注意:要遵循“两同两小一大”规则; “两同”–方法名要相同,形参列表要相同; “两小”–子类的方法返回值类型比父类方法返回值类型更小或相同; ”一大“–子类的方法访问权限应比父类的方法访问权限更大或相等;
构造器重载 要求:创建对象对象有更多的选择(灵活),形参列表肯定不同
java中的参数传递, ( 注意:引用类型传值传的是地址的值)
Java中只有值传递(面试中笔试常见题目)
基本数据类型:传递的值是传这个值的副本给形参
引用类型:传这个对象地址的值,把地址的值copy给实参,到方法中就是形参了
实参:就是调用方法时传递的值,比如 add(3,4); 3和4是实参
形参:是方法中定义的参数,比如 public int add(int a,int b){} 这里的a和b是形参
基本类型传递
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CzguELRI-1654063945468)(file:///C:\Users\27970\AppData\Local\Temp\ksohtml10668\wps1.jpg)]
对象数组
语法:类名 [] 数组名称 = new 类名 [数组长度]
创建对象:类名 对象名称=new 类名()
例:User user=new User()
User[] u=new User [length]
把对象赋值给对象数组:
u[i]=user
输出对象数组例的对象的元素方法
要在类里面重写toString方法,返回的内容要包含所有的对象属性
例:
//要重写toString方法,要不然对象数组输不出对象里的属性,重写返回什么属性就显示什么属性,继承的属性可以在子类一同写父类要显示的属性
对象属性包含job,num,sex,age,name
@Override
public String toString() {
return “Communist [job=” + job + “, num=” + num + “sex=” + sex + “, age=” + age + “, name=” + name + “]”;
}
显示的属性
对象属性包含job,num,sex,age,name
@Override
public String toString() {
return “Communist [job=” + job + “, num=” + num + “sex=” + sex + “, age=” + age + “, name=” + name + “]”;
}
面向对象的三大特征
1.封装
把不需要让外界知道的信息隐藏起来不让外界访问,或者允许外界访问使用但不允许外界做出修改。
面向对象的三大特征之一
字段要用private修饰
合理的隐藏 实现的细节隐藏起来,提供public void setXxx(具体的数据类型 变量){this.xxx = 变量}
合理的暴露 对外暴露访问字段的方法 比如 public 数据类型 get字段名(){ return 字段名;}
封装的优点有以下几点
-
高内聚,低耦合
-
类内部的结构可以自由修改
-
隐藏某些信息的作用
-
提供对外暴露访问的方法设值
实现封装的步骤
1. 修改属性的可见性来限制对属性的访问(一般限制为private),例如:
public class Person {
private String name;
private int age;
这段代码中,将 name 和 age 属性设置为私有的,只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏。
2. 对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问,例如:
public class Person{
private String name;
private int age;
private boolean alive;
public int getAge()注意:手写容易出错,而且开发效率不高,所以用快捷方式 alt + shift + s 选择 generate getter and setter就可以得到setAge和gteAge
{
return age;
}
public void setAge(int age){
this.age = age;
}
public String getName()
{
return name;
}
public void setName(String name){
this.name = name;
}
public boolean isAlive() {
return alive;
}
public void setAlive(boolean alive) {
this.alive = alive;
}
注意:采用 this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突。
封装的使用细节:一般使用private访问权限
提供相应的get、set方法来访问相关属性,这些方法通常是public修饰的。以提供对属性的赋值与读取操作。(注意!boolean变量的get方法是is开头。)
一些只用于本类的辅助性方法,可以使用private修饰,希望其他类调用的方法用public修饰。
**this与super关键字:1. this关键字代表当前对象 2. super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类。 **
注意:super()和this()均需要放在构造方法的第一行内
2.继承
定义:就是子类继承父类的特征和行为,使得子类对象(实例)拥有父类的实例域和方法或子类从父类继承方法使得子类具有父类的相同行为
继承格式
class 父类()
class 子类 extends 父类{}
需要注意的是 Java 不支持多继承,但支持多重继承。
例:
继承的优点
-
子类拥有父类非 private 的属性、方法。
-
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
-
子类可以用自己的方式实现父类的方法,即重写父类方法。
-
继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类。
提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
3.多态
定义:是指同一个行为具有多个不同的表现形式或形态的能力
多态存在的三个必要条件
条件:
1 是继承关系
2 子类重写了父类的方法
3 父类调用了子类重写后的方法
类型:编译时多态和运行时多态。编译时多态取决于该变量所使用的类型,运行时由具体的实例来决定。
注意:编译时看左边,运行时看右边
**面试题:**什么是多态?实现多态的方法有哪些?
多态是面向对象的最后一个主要特征,它本身主要分为两个方面:
- 方法的多态性:重载与覆写
|-重载:同一个方法名称,根据不同的参数类型及个数可以完成不同的功能。
|-覆写:同一个方法,根据操作的子类不同,所完成的功能也不同。- 对象的多态:父子类对象的转换。
|-向上转型:子类对象变为父类对象,格式:父类 父类对象 = new 子类实例,自动;—也叫对象实例化
|-向下转型:父类对象变为子类对象,格式:子类 子类对象 = new (子类)父类实例,强制。–也叫对象实例化
//向上转型
//父类引用子类对象
Animal a = new Dog();
//父类调用了子类重写父类的方法
//没有运行的时候,按住ctrl键,用鼠标移到eat()这个方法上面,点击 然后会指向到父类的eat(),这就是编译时看左边
判断多态具体代码
//父类
public class Animal {
public void eat() {
System.out.println("动物 :吃饭");
}
public void shout() {
System.out.println("动物 :叫声");
}
}
//子类继承父类
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫:吃猫粮");
}
@Override
public void shout() {
System.out.println("猫:喵喵叫");
}
}
//调用方法
public class Demo {
public static void main(String[] args) {
// 不符合多态条件,所以不是多态
Dog d = new Dog();
d.eat();
d.shout();
//向上转型
//父类引用子类对象
Animal a = new Dog();
//父类调用了子类重写父类的方法
//没有运行的时候,按住ctrl键,用鼠标移到eat()这个方法上面,点击 然后会指向到父类的eat(),这就是编译时看左边
a.eat();
a.shout();
}
多态实现方式:抽象类和抽象方法,接口
抽象(abstract)不能与那些关键字共存?
1).private :因为一个abstract方法需要被重写,所以不能修饰为private;
2).final:因为一个abstract方法需要被重写。被final修饰的方法是不能被重写的,所以不能同final共存;
3).static:因为一个abstract方法没有方法体。静态方法需要对方法体执行内容分配空间,所以不能同static共存;(abstract是没有实现
的,不能产生对象,而是static是属于类的,类本身是已经存在的对象) 4).synchronized:
是同步的,然而同步需要具体的操作才能同步,但,
abstract是只有声明没有实现的(即,使用synchronized关键字的是需要有具体的实现同步的操作的,但是使用abstract是只有声明而没有实现的,这样就产生了冲突)
5).native:他们本身的定义就是冲突的,native声明的方法是移交本地操作系统实现的,而abstract是移交子类对象实现的,同时修饰的话,导致不知道谁实现声明的方法
抽象
注意:
/*
* 有抽象方法的类一定是抽象类
* 抽象类不一定有抽象方法
*/
修饰方法,类
抽象,一般作为模板使用。
模板就是一部分不变的,另外一部分可以被子类继承后扩展的一个算法骨架
用abstract修饰一个类后,这个类是不能new对象的
有抽象方法的类一定是抽象类
抽象类不一定有抽象方法
抽象类----//是在class 前加abstract变成抽象类
**抽象方法—//变成抽象方法要用abstract修饰方法 **
语法:abstract 返回类型 方法名(){} 没有方法体
代码:
//**抽象类
abstract class Bird{
//变成抽象方法要用abstract修饰方法 abstract 返回类型 方法名(){} 没有方法体
public abstract void layEggs();//抽象方法
public abstract void fly();
public void say() {
System.out.println("我是Bird的say()....");
}
}
注意: 继承抽象类必须重写抽象类的抽象方法,不然,此类要作为抽象类
例如:
class Eagle extends Bird{
@Override//重写父类得抽象方法
public void layEggs() {
System.out.println("老鹰下蛋");
}
@Override//重写父类得抽象方法
public void fly() {
System.out.println("老鹰可以飞得很高...");
}
}
//抽象类不能创建自身的实例—不能new自身类的得对象
//抽象类 是有得有失 得到抽象的能力 失去了创建实例的能力
抽象一般用作模板:例:
abstract class Cooker{
//算法的骨架
void doWork() {
//起锅烧油
System.out.println("起锅烧油");
//doCooking
doCooking();
//端菜上桌
System.out.println("端菜上桌");
}
//抽象方法
abstract void doCooking();
}//以上便是模板
class 张厨子 extends Cooker{
//具体化模板得内容
@Override
void doCooking() {
System.out.println("佛跳墙...");
}
}
class 李厨子 extends Cooker{
@Override
void doCooking() {
System.out.println("开水白菜...");
}
}
public class CookingDemo {
public static void main(String[] args) {
Cooker c = new 张厨子();
c.doWork();
System.out.println("-------------");
Cooker c2 = new 李厨子();
c2.doWork();
}
}
instanceof
instanceOf 判断是否是父子关系
//比较安全的做法
if(p instanceof Chinese) {
}
接口-interface
接口是Java里面的规范,标准
接口用interface表示 ,
继承语法:类B implements A{} 就可以获得接口A常量,需要重写接口A中抽象方法
接口中成员有:jdk1.7(包含)常量,抽象方法
Jdk1.8(包含)后,除了常量,抽象方法,还有新添加了static/default方法
系统会自动为接口里定义的成员变量增加Public static final修饰符,因此接口里的成员变量都是静态常量。//加上static final修饰符后,该成员就不能被重写,里面的属性不能被修改
java类只有单继承,接口可以多继承,接口的出现就是为了弥补抽象类的不足。
接口 C extends A,B{}
接口中成员有:jdk1.7(包含)常量,抽象方法
接口和抽象类区别:
成员 | 抽象类 | 接口类1.7 | 接口类1.8后 |
---|---|---|---|
字段 | 普通字段,常量 | 常量 | |
方法 | 普通方法,抽象方法 | 抽象方法 | 新添加了static/default方法 |
代码块 | 可以有 | 不能有 | |
构造器 | 有,不完整 | 没有 |
相同点:都不能new自身的对象!
接口里的普通方法不能有方法体,但类方法和默认方法都必须有方法体
默认方法前面加default修饰
注意:类方法要有static修饰,默认方法只能有default修饰,不能有static修饰
例:
public interface Output{
int a=50;//常量
void out();//普通方法,默认有public abstract修饰
void getData(String…msgs)//同上
default void print(String…msgs){ //默认方法
System.out.println();
}
static String text(){//定义类方法具体看java讲义P148页
return “”;
}
}
当接口A和接口B同时拥有相同的方法时,主类继承这两个接口后必须重写这个相同的方法,要不然会报错。例:
interface A{
void fly();
}
interface B {
void fly();
}
public class 测试二 implements A,B{//测试二会报错,报错内容为The type 测试二 must implement the inherited abstract method B.fly()
@Override
public void fly() {
// TODO Auto-generated method stub
public static void main(String[] args) {}
}
正确的代码
代码一:package com.gec.oop5;
//读的接口
interface Read{
void read();
}
//写的接口
interface Write{
void write();
}
interface USB extends Read,Write{
//静态方法 可以读取文件
static void testStatic() {
System.out.println("接口的static方法");
}
//default方法
default void testDefault() {
System.out.println("接口的default方法");
}
}
class Mouse implements USB{
@Override
public void read() {
System.out.println("鼠标可以读");
}
@Override
public void write() {
System.out.println("鼠标不能写");
}
}
class HardDisk implements USB{
@Override
public void read() {
System.out.println("往移动硬盘写内容");
}
@Override
public void write() {
System.out.println("往别的地方写内容");
}
}
public class InterfaceDemo3 {
public static void main(String[] args) {
USB u = new HardDisk();
u.read();
u.write();
//调用接口中的静态方法
USB.testStatic();
//由具体的类实现调用default方法
u.testDefault();
}
}
代码二:package com.gec.oop5;
interface Bird{
int age = 3;//常量 public static final int age; 会加上public static final修饰变量
void layEggs();//抽象方法 会默认加上 public abstract 修饰方法
void fly();
}
class Eagle implements Bird{
@Override
public void layEggs() {
System.out.println("老鹰下蛋");
}
@Override
public void fly() {
System.out.println("老鹰飞翔");
}
}
class Ostrich implements Bird{
@Override
public void layEggs() {
System.out.println("鸵鸟下蛋");
}
@Override
public void fly() {
System.out.println("鸵鸟不能飞");
}
}
public class BirdDemo {
public static void main(String[] args) {
//左边是大类,右边是小类 向上转型
Bird b = new Eagle();
//父类调用子类重写后的方法
b.fly();
System.out.println("-------------");
Bird b2 = new Ostrich();
b2.fly();
}
}
内部类
在一个类A的内部再创建别的类B,类中类,这个类B就称之为内部类,类A称之为外部类。
好处:
1 内部类可以有自己的实例,有自己的信息,使用是更安全
2 可以写驱动程序(比如安卓)、AWT/Swing
3 写异步调用
分类:
静态内部类
非静态内部类
匿名内部类局部内部类
静态内部类
public class StaticInnerDemo {
static String name = "admin";
//在类前面用static修饰就可以定义一个静态内部类
static class Inner{
int age = 3;
void test() {
System.out.println("这是Inner的test()");
//访问外部类属性
System.out.println("name:" + name + ",age:" + age);
}
}
public static void main(String[] args) {
//创建静态内部类实例
Inner in = new Inner();
in.test();
}
}
非静态内部类(成员内部类)
非静态内部类对象实例化语法:外部类名称 . 非静态内部类名称 非静态内部类对象=new 外部类名称() . new 非静态内部类名称();如下代码所示
public class NoStaticInnerDemo2 {
class Inner{
int age = 3;
void test() {
System.out.println("这是非静态内部类test()....");
}
}
public static void main(String[] args) {
//先创建外部类的实例.new 内部类
NoStaticInnerDemo2.Inner nsd = new NoStaticInnerDemo2().new Inner();
//调用方法
nsd.test();
//Inner in = nsd.new Inner();
}
}
匿名内部类
package com.gec.oop6;
public class AnonymousDemo3 {
public static void main(String[] args) {
A a = new A() {
@Override
void test() {
System.out.println("继承于抽象类A的test()");
}
};
a.test();
System.out.println("----------------");
//创建匿名对象2
B b = new B() {
@Override
public void test2() {
System.out.println("这是实现接口B的方法test2()");
}
};
b.test2();
}
}
abstract class A{
abstract void test();
}
interface B{
void test2();
}
局部内部类
在方法外面类里面,在代码块里,在方法体里
实例化方式:和正常类实例化方式一样 --局部内部类名称 局部内部类对象=new 局部内部类名称();
package com.gec.oop6;
import java.awt.Button;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class LocalInnerDemo4 {
String name = "admin";
{
class A{
String name = "老王";
int age = 3;
public void test3() {
String name = "老刘";
System.out.println("test3()...");
//面试题
System.out.println("name:" + name);//老刘
System.out.println("this.name:" + this.name);//老王
//访问外部类属性
System.out.println("LocalInnerDemo.this.name:" + LocalInnerDemo4.this.name);//admin
}
}
A a = new A();
a.test3();
}
public void test() {
class B{
}
B b = new B();
}
public static void main(String[] args) {
class C{
}
//创建C的实例
C c = new C();
LocalInnerDemo4 lid = new LocalInnerDemo4();
}
}
关键字:final
意思: 最终的,最后的
Final可以修饰类,修饰方法,修饰属性,jdk类库中有String,Number,Integer,Float…
- 修饰类,这个类不能用于继承
- final修饰方法,这个方法不能被子类重写
- 修饰变量,该变量不能被重复赋值
代码
package com.gec.oop5;
final class A{
}
// 类B不能继承类A
// class B extends A{}
class C{
//final修饰方法,这个方法不能被子类重写
final void test() {
System.out.println("这是c的test()");
}
}
class D extends C{
/*
final void test() {
System.out.println("test()");
}
*/
}
public class FinalDemo2 {
//USER :被 称为常量,不可变的变量 ,工具里面的属性叫常量
public static final String USER = "root";
//修饰变量
final String name = "admin";
{
final String b;
b = "张三";
}
//可以用在形参
public void test(final String name2) {
String str2 = name2;
}
public static void main(String[] args) {
final String b;
b = "张三";
//不能被重复赋值
//b = "李四";
}
}