Java SE-面向对象
1、什么是面向对象
-
面向对象编程(oop):物以类聚,分类的思想模式。就是先把问题分类,再对这些分类问题进行思考,最后才是对分类下的细节进行面向过程处理。
-
面向对象编程的本质:**以类的方法组织代码,以对象的组织(封装)数据**;
-
抽象:把共同的地方抽取出来(把像的地方抽出来组成类);
-
三大特性:封装,继承,多态;
-
认识:从认识论考虑,现有对象后有类。对象是具体的事物,类是抽象的,是对对象的抽象;
-
实践:从代码的运行角度考虑,现有类后有对象,类是对象的模板。
//对象的创建
public class Student {
String name;
double age;
public void study(){
System.out.println(name+"在学习");
}
}
/*
Student xiaomao = new Student();//类具体为对象
Student xiaohong = new Student();
xiaomao.name = "xiaomao";//为对象赋值
xiaomao.study();//xiaomao在学习
xiaohong.study();//null在学习
2、构造函数
-
构造函数和类名相同,没有返回值,且不能写void
-
一个类即使什么都不写,都会存在一个构造器
-
new类,本质是在调用构造函数,原来初始化对象的值;根据函数的个数类型,默认调用相应的构造函数,新建对象时,根据调式时步骤,会先去类里调用构造函数,才会生成具体对象
-
alt+insert,自动生成构造函数
-
如果需要初始化参数个数不同的对象,需要新建多个构造函数;
-
如果定义了有参构造,必须手动创建一个无参构造函数
/*构造函数和类名相同,没有返回值,且不能写void
1、一个类即使什么都不写,都会存在一个构造器
2、new类,本质是在调用构造函数,原来初始化对象的值
3、alt+insert,自动生成构造函数
4、如果需要初始化参数个数不同的对象,需要新建多个构造函数;
5、如果定义了有参构造,还想创建无参对象,必须手动创建一个无参构造函数
*/
public class Person {
String name;
int age;
//初始化name
public Person(String name) {
this.name = name;
}
//初始化age
public Person(int age) {
this.age = age;
}
//同时初始化name&age
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
/*
Person person = new Person("唐",4);//根据函数的个数类型,默认调用相应的构造函数
Person person1 = new Person("唐");//新建对象时,根据调式时步骤,会先去类里调用构造函数,才会生成具体对象
Person person2 = new Person(7);//
System.out.println(person.name);
System.out.println(person.age);
*/
3、创建对象内存分析
package opp.demo03;
public class Pet {
public String name;//公共类才能被引入的包调用,如果同一个包可以不用加public
public int age;
public void shout(){
System.out.println("叫了一会");
}
}
/*
Pet dog = new Pet();
dog.name = "小强";
dog.age = 3;
dog.shout();
System.out.println(dog.age);
System.out.println(dog.name);
*/
4、封装
-
该露的露,该藏的藏:我们程序设计时要追求“高内聚,低耦合”。高内聚:就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少了的方法给外部使用。
-
封装:通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息的隐藏。
-
属性私有:set/get
public class Student {
private String name;
private int age;
private char sex;
//私有的参数,需要创建方法来设置(set)和获取(get)它才可以
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
if(age ==0){
System.out.println("设置了非法值");
}
return age;
}
public void setAge(int age) {
if(age<=120||age>=0){
this.age = age;
}else{
this.age = 0;
}
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
}
/*
Student s1= new Student();
s1.setName("张三");
s1.setAge(999);//一看这里的年龄就不会,学生年龄不可能有999岁,可以在设置年龄的方法里面加限制条件
System.out.println(s1.getName());
System.out.println(s1.getAge());
*/
5、继承
-
继承的本质就是对类的抽象化,从而对现实世界更好的建模
-
extends意思是扩展,子类是父类的扩展,私有的参数无法被直接调用,私有的方法无法被继承;
-
Java中只有单继承,没有多继承;(儿子只能有一个爸爸或是爷爷,爸爸可以有几个儿子...)
-
继承是类和类之间的一种关系,除此之外类和类之间还有依赖,组合,聚合等关系;
-
子类和父类之间,从意义上讲是“is a”关系,如:旺财是一只狗
-
所有类都会继承object类(object类可以说是老祖宗,一脉单传)
-
super (重点)
-
方法重写 (重点)
import opp.demo05.Student;
import opp.demo05.Teacher;
public class Application {
public static void main(String[] args) {
Student student = new Student();
Teacher teacher = new Teacher();
student.say();
teacher.say();
}
}
/*
public class Person {
private int money = 10_0000_0000;
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public void say(){
System.out.println("会说话");
}
}
public class Student extends Person{
}
public class Teacher extends Person{
}
*/
6、Super
-
super调用符类的构造方法,必须在构造方法的第一个
-
super必须只能出现在子类的方法或者构造方法中;
-
super和this不能同时调用构造方法;
代表对象不同 | 前提 | 构造方法 | |
---|---|---|---|
super | 代表父类对象的应用 | 只能在继承条件下才可以使用 | 父类的构造 |
this | 本身调用者这个对象 | 没有继承也可以使用 | 本类的构造 |
import opp.demo05.Student;
import opp.demo05.Teacher;
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
s1.test();
}
}
/*
public class Person {
public Person(String name) {
System.out.println("Person无参构造函数被调用");
}
protected String name = "人类";
//私有的方法不能被继承,改为私有,子类的super.print()方法会出错
public void print(){
System.out.println("Person");
}
}
/————————————————————————————————————————————————————————————————————————————
public class Student extends Person{
public Student() {
//隐藏了一个代码:super();自动调用父类的构造器,必须放在子类构造器的第一行
super("hello");//
//this("hello");//调用自己的构造函数,构造函数里不能同时调用自身的构造函数和父类构造函数
System.out.println("Student的无参构造函数被调用了");
}
public Student(String name) {
super("Person");
this.name = name;
}
private String name = "学生";
public void print(){
System.out.println("Student");//起名,调用的是本方法的参数
}
public void test(){
print();
this.print();
super.print();
}
}
*/
7、方法重写
-
重写:需要有继承关系,子类重写父类的方法;
-
方法名必须相同;
-
参数列表必须相同;
-
修饰符:范围可以扩大但不能缩小,public->Protected->Default->private
-
抛出的异常:范围可以缩小,但是不能扩大:ClassNotFoundException--->Exception(范围大)
-
重写,子类的方法和父类的必须一致,方法体不同
-
为什么要重写方法:1、父类的功能子类不一定需要,或者不一定满足;2、Alt+Insert快捷键,选择override;
import opp.demo06.B;
import opp.demo06.A;
//非静态方法和静态方法有很大的区别
public class Application {
public static void main(String[] args) {
//静态方法:方法的调用只和左边定义的引用类型有关
//非静态方法:跟调用创建的对象有关
B b = new B();
b.test();
//父类的引用指向子类b
A a =new B();//重写非静态的方法,关键字必须是public才可以重写
a.test();//重写后都是等于
}
}
public class B extends A{
//重写
@Override//注释,有功能的注释
public void test() {
System.out.println("Btest");
}
}
public class A {
public void test(){
System.out.println("Atest");
}
}
8、多态
注意事项
-
多态是方法的多态,属性没有多态
-
父类和子类之间有联系才能强制转换类型;ClassCastException!
-
多态存在条件:1、有继承关系;2、方法需要重写;父类的引用指向子类对象!father f1 = new son();
不能重写的有:1、static 方法,属于类,不属于实例;2、final常量;3、private方法,私有的
//多态:有继承关系,且重写了父类的方法,对象调用重写后的方法才会出现多态
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//可以指向的引用类型就不确定了,父类的引用可以指向子类,祖父类的引用也可以指向子类
//Student能用的方法都是自己的或是父类的
Student s1 = new Student();
//当引用为Person父类时,可以指向子类,但是不能调用子类独有的方法
Person s2 = new Student();
Object s3 =new Student();
//对象能执行哪些方法,主要看对象左边类型,和右边关系不大!
s1.run();//子类继承父类的全部方法
s2.run();//
s1.eat();
//s2.eat();//当引用为Person父类时,可以指向子类,但是不能调用子类独有的方法
((Student)s2).eat();//强制转换为子类后可以调用子类的方法
}
}
/*
public class Person {
public void run(){
System.out.println("run");
}
}
public class Student extends Person{
//重写了父类的run()方法
@Override
public void run() {
System.out.println("test");
}
public void eat(){
System.out.println("eat");
}
}
*/
9、instanceof和类型转换
-
这个关键字的用法是:A instanceof B ,返回值为boolean类型,用来判断A是否是B的实例对象或者B子类的实例对象,A和B是否为父子关系,爷孙关系。如果是则返回true,否则返回false。
import opp.demo07.Person;
import opp.demo07.Student;
import opp.demo07.Teacher;
// instanceof :这个关键字的用法是:A instanceof B ,
// 返回值为boolean类型,用来判断A是否是B的实例对象或者B子类的实例对象。
// 如果是则返回true,否则返回false。
public class Application {
public static void main(String[] args) {
//Object>String
//Object>Person>Teacher
//Object>Person>Student
System.out.println("===============================");
Object s1 = new Student();//引用了一个object指向Student
System.out.println(s1 instanceof Student);//结果为ture
System.out.println(s1 instanceof Person);//结果为ture
System.out.println(s1 instanceof Object);//结果为ture
System.out.println(s1 instanceof Teacher);//结果为false
System.out.println(s1 instanceof String);//结果为false
System.out.println("===============================");
Person s2 = new Student();//引用了一个object指向Student
System.out.println(s2 instanceof Student);//结果为ture
System.out.println(s2 instanceof Person);//结果为ture
System.out.println(s2 instanceof Object);//结果为ture
System.out.println(s2 instanceof Teacher);//结果为false
//System.out.println(s2 instanceof String);//编译失败,s2跟String类无关系
System.out.println("===============================");
Student s3 = new Student();//引用了一个object指向Student
System.out.println(s3 instanceof Student);//结果为ture
System.out.println(s3 instanceof Person);//结果为ture
System.out.println(s3 instanceof Object);//结果为ture
//System.out.println(s3 instanceof Teacher);//编译失败,s3跟Teacher类无关系
//System.out.println(s3 instanceof String);//编译失败,s3跟String类无关系
}
}
类型转换
-
父类引用指向子类对象
-
把子类转为父类,向上转型
-
把父类转换为子类,向下转型:强制转换
-
方便调用,减少重复代码,代码简洁
public class Application {
public static void main(String[] args) {
//1、类型之间的转换: 父 >子 强制转换 ||| 子 >父 直接转换
//高 低 ==低转高
Person s1 = new Student();//直接把子类对象转为父类了,可能会丢失一些子类自己的方法
//高转低强制转换
((Student)s1).go();//强制把父类的对象转为子类,才能调用子类方法,懒得去写父类的代码了
}
}
10、Static小结
-
静态变量,内存里面只有一个,可以直接调用。 多线程!
-
非静态方法里面可以直接调用静态方法
-
非静态的方法不能直接调用,要在main方法里面创建对象才能被调用
-
整个程序静态代码只运行一次,不管新建几个对象都只执行一次。其他都是按对象创建个数执行
-
静态引入,直接调用;如:import static java.lang.Math.random;
-
类被final定义了,则不能被继承
public class Student {
private static int age;//静态变量,内存里面只有一个,可以直接调用。 多线程!
private double score;//非静态变量
public void run(){
go();//非静态方法里面可以直接调用静态方法
}
public static void go(){
}
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(s1.score);//
// System.out.println( Student.score);//编译出错,非静态变量不能直接调用
System.out.println( Student.age);
System.out.println( s1.age);
//run();//非静态的方法不能直接调用
go();//静态的方法可以直接调用
}
}
public class Person {
{
System.out.println("匿名代码块");
}
//整个程序静态代码只运行一次,不管新建几个对象都只执行一次。
// 其他都是按对象创建个数执行
static{
System.out.println("静态代码块");
}
public Person() {
System.out.println("构造代码块");
}
public static void main(String[] args) {
new Person();//第一次先执行静态代码块,匿名代码块,构造代码块;
System.out.println("=============");
Person s1 = new Person();//第二次先执行匿名代码块,构造代码块;
}
}
import static java.lang.Math.random;//静态引入
public class Test {
public static void main(String[] args) {
System.out.println(random());//直接调用
}
}
11、抽象类
-
不能new抽象类,只能靠子类去实现它
-
抽象类中可以写普通方法
-
抽象方法必须写在抽象类中
-
抽象类存在构造器吗?因为抽象类不可实例化,那么只能在子类实例化时调用该抽象类的构造器才有用
-
父类是抽象类,子类是一般类,那么子类需要重写父类中的抽象方法
-
父类是抽象类,子类也是抽象类,那么父类的抽象类可以不用重写
//抽象类中可以有抽象的方法和一般方法,但是抽象方法一定要在抽象类中
//父类是抽象类,子类是一般类,那么子类需要重写父类中的抽象方法
//父类是抽象类,子类也是抽象类,那么父类的抽象类可以不用重写
public abstract class Person {
//抽象方法,只有抽象名,没有具体的实现,需要子类去实现
public abstract void run();
public Person() {
System.out.println("无参构造");
}
/*
1、不能new抽象类,只能靠子类去实现它
2、抽象类中可以写普通方法
3、抽象方法必须写在抽象类中
4、抽象类存在构造器吗?因为抽象类不可实例化,那么只能在子类实例化时调用该抽象类的构造器才有用
*/
}
public class Test extends Person{
public Test(){
super();
}
@Override
public void run() {
}
public static void main(String[] args) {
Test test = new Test();
}
}
12、接口
-
接口:只有抽象的方法,无法自己写方法;接口的本质是契约,类继承接口后,需要按接口里面的方法规则去实现方法;接口中一般不放常量;
-
接口的目的:架构师定义接口名,程序员实现创建了实现接口
-
接口类标志:interface,接口类只有方法名,不写实现方式;
-
类可以继承多接口,实现接口的类,需要重写接口中的方法;
/*
1、接口类标志:interface
2、接口类只有方法名,不写实现方式;
3、
*/
public interface UserService {
public void Update();
public void Delete();
public void Query();
public void run();
}
public interface TimerService {
public void Timer();
}
/*
1、接口可以实现多继承
2、实现接口的类,需要重写接口中的方法
3、
*/
public class UserServiceImpl implements UserService,TimerService{
@Override
public void Timer() {
}
@Override
public void Update() {
}
@Override
public void Delete() {
}
@Override
public void Query() {
}
@Override
public void run() {
}
}
13、内部类
-
内部类可以直接获取外部类的方法和常量
-
注意如何创建内部类的对象:
//如何创建内部类,先创建外部类对象
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
public class Outer {
int id = 10;
public void test(){
System.out.println("外部类测试");
}
public class Inner{
public void run(){
System.out.println("内部类测试");
}
//获得外部类的私有属性,常量和方法
public void GetId(){
System.out.println(id);
test();
}
}
}
public class Application {
public static void main(String[] args) {
//如何创建内部类,先创建外部类对象
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.GetId();
}
}