面向对象
初识面向对象
- 面向对象本质:以类的方式组织代码,以对象的方式组织(封装)数据;
方法回顾与加深
方法定义
/*
修饰符 返回值类型 方法名(...) throws 异常{
//方法体
return 返回值;
}
*/
- 修饰符:
- 四种权限修饰符:public 、 protected 、 default 、 private
- static:static属性和方法都可以直接通过类名调用,只执行一次,且每一个类所有对象共享同一个static属性/方法;
- final:常量,不能被继承;
- 返回类型:
- break和return区别:
- break:结束循环或者switch语句
- return:结束方法,返回一个值(可以无返回值)
- 方法名:
- 参数列表:
- 异常抛出:
方法调用
- 静态方法:可以直接通过类名.方法名调用;和类同时加载,属于类;
public static void main(String[] args){
int sum = add(1,2);//在同一个类中可省略类名调用
System.out.println(sum);
//输出3
}
public static int add(int a, int b){
return a+b;
}
- 非静态方法:需要先new一个对象,才能使用对象名.方法名调用;需要new对象和才加载,属于对象;
public class Demo01{
public static void main(String[] args){
Demo02 demo02 = new Demo02();
int sum = demo02.add(1,2);
System.out.println(sum);
//输出3
}
}
class Demo02{
public int add(int a, int b){
return a+b;
}
}
-
形参和实参:
- 形参:上述代码中add方法定义时int a,int b,其中a,b就是形参;
- 实参:上述代码中调用add方法时传入的1,2就是实参;
-
值传递和引用传递:
-
java中全部是值传递,值传递就是将1,2这两个值复制一份给a,b分别赋值,修改形参的值并不会影响形参的值;
-
引用传递就是将内存中存放实参的内存地址传给了形参,从而修改形参的值实际上也会修改实参的值;传递对象时和引用传递相似:
public class Demo03 { public static void main(String[] args) { Person person = new Person(); //只是创建了一个对象,并未给对象赋值,所以person.name = null; System.out.println(person.name); //调用reName方法后,将整个对象的地址传递给reName方法 reName(person); System.out.println(person.name); } public static void reName(Person person){ //实质上这个person对象,指向的是 Person person = new Person();具体的对象,修改这里同时修改了实参中的数据 person.name = "刀刀木"; } } class Person{ String name; } /* null 刀刀木 */
-
-
this关键字:用来调用本类中成员变量,参照下一节代码;
对象创建分析
类
- 类是一种抽象的数据类型,是对某一类事物整体描述/定义,包括该类事物应具备的特点和行为,但是并不代表某一个具体事物;
public class Student {
//属性:字段
String name;
int age;
//方法
public void study(){
System.out.println(this.name+"在学习");
}
}
构造器
- 也就是构造方法;
- 方法名和类名相同;
- 未定义时每个类都有一个默认的构造方法;
- 构造方法可以不止一个,方法重载;
- 必须没有返回值类型,且不能定义void返回值类型;
- 实例化初始值,new对象时实质上是在调用构造方法;
- 一旦定义了有参构造,必须定义无参构造,
public class Person(){
String name;
public Person(){//无参构造,一般定义了有参构造之后无参构造内容常为空
this.name = "小明";
}
public Person(String name){//有参构造
this.name = name;
}
}
//快捷键 Alt+insert自动生成构造器
对象
- 对象是类的具体实例;
public class Application {
public static void main(String[] args) {
//实例化类
//类实例化后会返回一个自己的具体对象
Student xiaoMing = new Student();
Student xiaoHong = new Student();
System.out.println(xiaoMing.name);
System.out.println(xiaoMing.age);
xiaoMing.name = "小明";
xiaoMing.age = 3;
System.out.println(xiaoMing.name);
System.out.println(xiaoMing.age);
}
}
/*
null
0
小明
3
*/
创建对象内存分析
public class Application {
public static void main(String[] args) {
Pet dog = new Pet();
dog.name = "旺财";
dog.age = 3;
dog.shout();
Pet cat = new Pet();
}
}
//输出:旺财叫了一声
//在两个文件中,一个文件中只有一个类可用public修饰
public class Pet {
public String name;
public int age;
public void shout(){
System.out.println(this.name+"叫了一声");
}
}
- 大致内存分析如下:
面向对象三大特性
封装(数据的隐藏)
- 应禁止直接访问一个对象中数据的实际表示,而应通过接口来访问;
- 高内聚,低耦合
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
- 低耦合:仅暴露少量的方法给外部使用;
- 封装多对于属性而言,属性私有;
- 作用:
- 提高程序的安全性,保护数据;
- 隐藏代码的实现细节;
- 统一接口;
- 系统可维护性增强;
public class Application {
public static void main(String[] args) {
Student xiaoMing = new Student();
xiaoMing.setName("小明");
System.out.println(xiaoMing.getName());
xiaoMing.setAge(150);//不合法
//输入xiaoMing.getAge().sout得到下面输出代码:
System.out.println(xiaoMing.getAge());
}
}
/*
小明
3
*/
public class Student {
//属性私有
private String name; //名字
private int id; //学号
private char sex; //性别
private int age; //年龄
//提供一些可以操作这些属性的方法
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
//Alt+Insert自动生成get、set方法
public int getAge() {
return age;
}
public void setAge(int age) {
if(age>120||age<0)//安全性检查
this.age = 3;
else
this.age = age;
}
}
继承
- 类与类之间的一类关系,还有依赖、组合、聚合等关系;
- JAVA中只有单继承没有多继承;
- 继承关系的两头分别为父类和子类,子类继承父类通过关键字extends来表示;
- 子类可以继承父类非private的所有属性和方法;
- 构造方法不能被继承;
- 快捷键Ctrl+H查看继承树;
- JAVA中所有类都直接或间接继承自Object类;
- 子类通过super.属性/方法,可以调用父类属性或方法;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.setName("朝小闇");
student.say();//子类并未定义该方法,直接调用父类方法
System.out.println("==========================");
student.test("name");
student.test2();
}
}
public class Person {
public String name = "刀刀木";
public Person() {
System.out.println("Person无参构造器执行了");
}
public void setName(String name){
this.name = name;
}
public String getName() {
return name;
}
public void say(){
System.out.println("Person说话了");
}
}
public class Student extends Person {
String name;
public Student() {
/*默认先调用父类无参构造器:super();
如果显示调用super(),必须放在第一行中
如果显示调用this(name),也必须放在第一行
所以显示调用时只能调用父类或子类构造器,不能同时调用两者
*/
System.out.println("Student无参构造器执行了");
System.out.println("==========================");
}
public Student(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
public void test(String name){
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);//private 权限父类属性无法调用
System.out.println("==========================");
}
public void test2(){
System.out.println(getName());
System.out.println(this.getName());
System.out.println(super.getName());
System.out.println("==========================");
}
}
/*
Person无参构造器执行了
Student无参构造器执行了
==========================
Person说话了
==========================
name
朝小闇
刀刀木
==========================
朝小闇
朝小闇
刀刀木
==========================
Process finished with exit code 0
*/
方法重写
-
只有非静态方法可以重写;
-
只可重写public权限方法;
-
只存在子类和父类方法之间;
-
方法名必须相同;
-
参数列表必须相同;
-
修饰符:范围可以扩大不能缩小 public > protected > default > private
-
抛出的异常:可以被缩小但不能扩大,ClassNotFoundException < Exception
-
方法体不同;
-
普通调用:
public class Application {
public static void main(String[] args) {
A a = new A();
a.test();
B b = new B();
b.test();
}
}
public class A {
public void test(){
System.out.println("A进行测试");
}
}
public class B extends A {
public void test(){
System.out.println("B进行测试");
}
}
/*
A进行测试
B进行测试
*/
- 定义类型和创建类型不一致时(只有继承对象可以使用,上下都可转):
public class Application {
public static void main(String[] args) {
//静态方法调用
//非重写,方法调用只和左边定义的数据类型相同
C c = new D();
c.test();
D d = new D();
d.test();
//非静态方法重写调用
//将父类引用指向了子类
A a = new B();
a.test();
B b = new B();
b.test();
}
}
public class A {
public void test(){
System.out.println("A进行测试");
}
}
public class B extends A {
public void test(){
System.out.println("B进行测试");
}
}
public class C {
public static void test(){
System.out.println("C进行测试");
}
}
public class D extends C {
public static void test(){
System.out.println("D进行测试");
}
}
/*
C进行测试
D进行测试
B进行测试
B进行测试
*/
多态
-
同一对象的方法可以根据发送对象的不同而采取多种不同的行为;
-
一个对象的实际类型是确定的,但可以指向对象的引用类型有很多;
-
多态存在的条件:
- 有继承关系;
- 子类重写父类方法;
- 父类引用指向子类对象;
-
多态是方法的多态,属性没有多态;
-
类型转换异常:ClassCastException
-
static、final(存在常量池中)、private方法不能重写也就没有多态;
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//new Student();
//new Person();
//可以指向的引用类型不确定:父类的引用指向子类
//右边是创建的实际类型,左边是定义的引用类型
//能调用的方法都是自己的或继承父类的
Student s1 = new Student();
//可以指向子类,但是不能调用子类独有的方法
Person s2 = new Student();
Object s3 = new Student();
s1.run();
s2.run();//子类重写了父类方法,运行子类方法
s1.eat();
//s2.eat();//该句不能执行,对象能执行什么方法看左边引用类中是否含有,具体执行时还要看子类是否重写
((Student) s2).eat();//由高转低,可以执行
}
}
public class Person {
public void run(){
System.out.println("run");
}
}
public class Student extends Person {
public void run(){
System.out.println("son");
}
public void eat(){
System.out.println("eat");
}
}
/*
son
son
eat
eat
*/
instanceof
- X instanceof Y,只要X、Y之间存在父子关系即相似
public class Application {
public static void main(String[] args) {
//Object > String
//Object > Person > Student
//Object > Person > Teacher
Object object = new Student();
System.out.println(object instanceof Student);
System.out.println(object instanceof Person);
System.out.println(object instanceof Object);
System.out.println(object instanceof Teacher);
System.out.println(object instanceof String);
System.out.println("=============================");
Person person = new Student();
System.out.println(person instanceof Student);
System.out.println(person instanceof Person);
System.out.println(person instanceof Object);
System.out.println(person instanceof Teacher);
// System.out.println(person instanceof String);
// 编译时直接报错
System.out.println("=============================");
Student student = new Student();
System.out.println(student instanceof Student);
System.out.println(student instanceof Person);
System.out.println(student instanceof Object);
// System.out.println(student instanceof Teacher);
// System.out.println(student instanceof String);
// 编译时直接报错
System.out.println("=============================");
}
}
/*
true
true
true
false
false
=============================
true
true
true
false
=============================
true
true
true
=============================
Process finished with exit code 0
*/
方法的强制转换
public class Application {
public static void main(String[] args) {
Person obj = new Student();
//把父类转换成子类,向下转型,强制转换
((Student)obj).go();
Student student = new Student();
student.go();
//把子类转换成父类,向上转型,直接转换,可能会丢失子类方法
Person person = student;
}
}
杂
public class Person {
{
System.out.println("匿名代码块");
}
static{
System.out.println("静态代码块");
}
public Person() {
System.out.println("构造方法");
}
public static void main(String[] args) {
Person person = new Person();
}
}
/*
静态代码块
匿名代码块
构造方法
*/
//先加载静态代码,再加载匿名代码,最后才是构造方法
//静态导入包之后调用Math.random可以直接使用random()调用
import static java.lang.Math.random;
public class Test {
public static void main(String[] args) {
System.out.println(random());
}
}
//0.4934732130804633
抽象类和接口
抽象类
- 抽象方法,继承自抽象类的子类(自身非抽象类时)必须要重写抽象类的抽象方法;
- 只是一种约束,不能被new,只能被子类实现;
- 抽象类可以写普通方法,但抽象方法必须在抽象类中;
- 抽象类是单继承;
public abstract class Action {
//抽象方法,继承抽象类的子类(非抽象类)必须要重写抽象类方法
public abstract void doSomething();
}
public class A extends Action{
@Override
public void doSomething() {
}
}
接口
-
只有规范,无法写入具体方法;
-
约束和实现分离;
-
接口中所有定义方法都是默认public abstract;
-
接口都需要有实现类;
-
接口一般不定义常量,默认public static final;
-
接口和抽象类一样,不能直接被实例化,必须被实现;
-
implements可以实现多个接口,但是必须重写所有方法;
public interface UserService {//接口
void add();
void delete();
}
public class UserServiceImpl implements UserService {//接口实现类
@Override
public void add() {
}
@Override
public void delete() {
}
}
内部类
- 一个java文件中可以有多个class类(非内部类),但是只能拥有一个public类
成员内部类
- 成员内部类不使用static静态修饰的前提下可以访问外部类的私有属性;
- 在类中定义;
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.getId();
}
}
//10
public class Outer {
private int id = 10;
public void out(){
System.out.println("外部类方法");
}
public class Inner{//如果static化,则不能调用非static外部属性
public void in(){
System.out.println("内部类方法");
}
//可以调用外部类的私有属性
public void getId(){
System.out.println(id);
}
public Inner() {
}
}
}
匿名内部类
public class Test {
public static void main(String[] args) {
//没有名字初始化类,不用将实例保存到变量中
new Apple().eat();
//
UserService userService = new UserService() {
@Override
public void hello() {
}
};
}
}
class Apple{
public void eat(){
System.out.println("eat");
}
}
interface UserService{
void hello();
}
静态内部类
- public static class Inner{}
局部内部类
- 在方法中定义class被称作局部内部类;
{//如果static化,则不能调用非static外部属性
public void in(){
System.out.println("内部类方法");
}
//可以调用外部类的私有属性
public void getId(){
System.out.println(id);
}
public Inner() {
}
}
}
匿名内部类
public class Test {
public static void main(String[] args) {
//没有名字初始化类,不用将实例保存到变量中
new Apple().eat();
//
UserService userService = new UserService() {
@Override
public void hello() {
}
};
}
}
class Apple{
public void eat(){
System.out.println("eat");
}
}
interface UserService{
void hello();
}
静态内部类
- public static class Inner{}
局部内部类
- 在方法中定义class被称作局部内部类;