java面向对象
java面向对象编程
面向对象思想:
- 物以类聚,分类的思维模式。思考问题首先会解决问题需要那些分类
- 适合处理复杂的问题,适合多人的协作问题
面向对象的本质:以类的方式组织代码,以对象的组织(封装)数据
特征:
- 抽象
- 三大特性:封装,继承,多态
static
-
加了static的方法可以通过类名直接调用,否则需要实例化后调用
但是:类里:两个static方法(两个都不是static)可以相互直接通过方法名调用。但是一个static方法不能直接调用一个非static方法
原因:static和类一起加载,但是非static是类实例化后才存在,调用时后者不存在
-
同理,static修饰的属性也是一样可以通过类名直接调用,且所有的对象共享一个static属性
public class Student extends Person {
public static int a =10;
public static void main(String[] args) {
Student student = new Student();
student.a--;
Student student1 = new Student();
System.out.println(student1.a);
}
}
//out :9
-
静态代码块
只在第一次实例化调用
public class Student extends Person {
public static int a =10;
{
//代码块(匿名代码块)
System.out.println("匿名代码块");
}
static{
//静态代码块
System.out.println("静态代码块");
}
public Student(){
//构造器
System.out.println("构造器");
}
public static void main(String[] args) {
Student student = new Student();
System.out.println("--------------------");
Student student1 = new Student();
}
}
/*out:
静态代码块
匿名代码块
构造器
--------------------
匿名代码块
构造器
-
静态导入包
//正常情况下,Math.random //静态导入后 import static java.lang.Math.random; public class Student extends Person { public static void main(String[] args) { random(); } }
final
- 修饰类:不能被继承
- 修饰变量:不能被修改
- 修饰方法:不能被子类重写
值传递和引用传递
值传递(pass by value):在调用函数时,将实际参数复制一份传递到函数中,这样在函数中对参数进行修改,就不会影响到原来的实际参数;
引用传递(pass by reference):在调用函数时,将实际参数的地址直接传递到函数中。这样在函数中对参数进行的修改,就会影响到实际参数;
java是值传递
//值传递:
public class main {
public static void main(String[] args) {
int a=1;
main.change(a);
System.out.println(a);
}
public static void change(int number){
number=2;
}
}
//out:1
//引用传递:本质还是值传递
public class main {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
main.change(person);
System.out.println(person.name);
}
public static void change(Person person){
person.name="lihua";
//本处的person指向
}
}
class Person{
String name;
}
// out:null
// lihua
四种访问权限
java的访问权限有下面四种:
public--都可访问(公有)
protected--包内和子类可访问(保护)
不写(default)--包内可访问 (默认)
private--类内可访问(私有)
类和对象的关系
类是一种抽象的数据类型,它对某一种事物整体描述
对象是抽象概念的具体实例
public class main {
public static void main(String[] args) {
Person lihua = new Person();//实例化,lihua就是对象,person是类
}
}
class Person{
String name;
}
构造器
初始化对象值
new的本质是在调用构造器
public class main {
public static void main(String[] args) {
Person lihua = new Person("李华");
System.out.println(lihua.name);
}
//李华
}
class Person{
String name;
//无参构造器
public Person(){
name="人";
}
//有参构造器
public Person(String name){
this.name=name;
}
}
构造器:快捷键alt+insert
创建对象内存分析
对象是通过引用来操作的:栈-->堆
默认值:数字: 0.0 0
char:\u0000(空)
boolean:false
other:null
封装
封装就是数据的隐藏:禁止直接访问数据,而应该通过操作接口来访问,这就是数据隐藏
程序设计追求:高内聚,低耦合。
- 高内聚是指类的内部数据操作细节自己完成,不干涉。
- 低耦合:仅仅暴露少量的方法给外部使用
public class Student {
// 属性私有
private String name;
private int id;
//设置get,set
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
get:获得数据
set:修改数据
快捷键alt+insert
封装的作用
- 提高程序安全性,保护数据
- 隐藏代码实现细节
- 统一接口
- 提高了系统可维护性
继承
- 继承的本质是某一批类的抽象
- extends:拓展。子类是父类的拓展
- java只有单继承没有多继承
- 子类(派生类)继承父类(基类),使用关键词extends
- 子类可以继承父类非private或默认非包内的属性和方法
//父类
class Person{
char name;
public void say(){}
}
//子类
public class Student extends Person {
public static void main(String[] args) {
Student student = new Student();
student.say();
}
}
快捷键ctrl+H可以看到继承树
java所有类都直接或间接继承object
super
指父类
//父类
class Person{
protected String name="person";
public void say(){}
}
//子类
public class Student extends Person {
String name="Student";
public static void main(String[] args) {
Student student = new Student();
student.printName("main");
}
public void printName(String name){
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
}
//out:main
// Studnet
// person
另外:static方法是没有this和super的
//父类
public Person() {
System.out.println("父类构造方法被调用了");
}
//子类
public Student() {
//结果证明:此处隐藏代码super(),且只能在开头,否则报错,调用this()也必须在第一行,所以两者不能同时调用
System.out.println("子类构造方法被调用了");
}
//实例化后
/* out:父类构造方法被调用了
子类构造方法被调用了
默认调用父类的无参构造函数,否则手动调用有参super("name")
方法的重写
//方法的调用只和左边定义数据类型有关,要么是右边重写的左边方法
Person person = new Person();
//父类引用指向子类
Person person1 = new Student();
/*
当调用前面两者的同名静态方法,都是调用左边的静态方法
非静态方法,同名必须要重写,且后者调用的是student的重写方法
@Override //注解:有功能的注释
public void say() {
super.say();
}
//重写父类的say()方法
重写:
- 需要继承关系,
- 子类重写父类方法,方法名必须相同,参数列表必须相同,
- 修饰符:范围可以扩大,不能缩小(相对于父类,public>protect>default>private),但是父类如果是private的话不能算重写,是一个子类新增方法
- 抛出的异常:范围可以缩小,不能扩大(相对于父类)
idea快捷键alt+insert:override
总而言之,重写是对于一些父类的功能子类不需要或是需要一定的修改
多态
同一个方法可以发送对象不同采用多种不同的行为方式
一个对象的实际类型是确定的(new 类),但可以指向对象的引用类型很多(父类或者有关系的类)
//方法的调用只和左边定义数据类型有关,要么是右边重写的左边方法
Person person = new Person();
//父类引用指向子类
Person person1 = new Student();
简而言之,有没有方法看左边,怎么实现方法看右边(非静态)。左边有就代表该方法存在可以调用,具体实现方法就看右边重写的
-
多态是方法的多态,属性没有多态
-
父类和子类有联系,否则类型转换异常ClassCastException!
-
存在条件:继承,方法需要重写,父类引用指向子类对象
-
无法重写的:static :不属于实例
final:常量
private方法
快捷键alt+回车 (new Student()==》补充选择引用)
instanceof
判断对象是什么类型
//Person 父类 ,teacher和student 子类
Person student = new Student();
if (student instanceof Student) {
System.out.println("Student");
}
if (student instanceof Teacher) {
System.out.println("Teacher");
}
if (student instanceof Person) {
System.out.println("Person");
}
if (student instanceof Object) {
System.out.println("Object");
}
/* out :Student
Person
Object
类型转换
//go是子类student方法
Person student = new Student();
//父类转子类向下转型(高转低)
((Student) student).go();
Student student1 =new Student();
//子类转父类向上转型(低转高),丢失go方法
Person person = student1;
person.go(); //error
一个有趣的现象
Person person = new Person();
//父类引用指向子类
Person person1 = new Student();
System.out.println(person.getClass());
System.out.println(person1.getClass());
/*class com.xxx.Person
class com.xxx.Student
尽管编译时识别为左边的父类对象,但是使用getclass或者getname方法时依旧删除的右边的子类对象。这个原因跟调方法调的是子类的方法一样,就是因为编译器编译时,载入的是父类, 但是编译时会把 子类独有的 属性和方法屏蔽掉,然后才会 按照子类的模板生成对象。所以 getClass getName是子类的,而作为参数会被认为是父类的。
总结:编译看左,实现看右。父类的引用对象指向了子类的实例对象。当调用person1时是在调用父类的引用对象,而父类的正在运行的引用对象有指向了子类的实例对象。getClass()返回的是对象运行时的类型即实例对象,另外super,this的getClass实际上也是运行的getClass,等同于无前缀的getClass
class Student extends Person
{
public void printTest()
{
System.out.println(super.getClass());
}
public void printTest2()
{
System.out.println(this.getClass());
}
public void printTest3()
{
System.out.println(getClass().getSuperclass());
}
}
// out :class Student
//class Student
//class Person
//如果只得到类名:getClass().getName()
抽象类
用abstract修饰的类
用abstract修饰的方法:抽象方法,只有名字,没有实现,抽象方法子类必须重写实现,除非子类是抽象类
抽象类:
- 不能被new,只是一个约束
- 只要有抽象方法必须是抽象类,但是抽象类不一定全是抽象方法
- 提高开发效率
- 存在构造器
局限:单继承,接口实现多继承
public abstract class Student {
public abstract void go();
}
接口
只有规范,自己不能写方法(抽象类具体实现和规范都有)
定义一组规则
关键词interface
接口不能被实例化,没有构造方法
接口的所有定义都是抽象的:
定义的方法默认默认public abstract
定义的属性是默认public static final,final必须有具体值
public interface UserService {
//默认public static final
int a=0;
//默认public abstract
void add(String name);
}
实现接口关键词:implements
实现接口必须重写接口的所有方法
接口可以多实现
public class Student implements UserService ,OtherService{
@Override
public void add(String name) {
}
}
内部类
在类的内部再定义一个类
-
成员内部类
public class Student { class Inner{ public void in(){ } } public static void main(String[] args) { Student student = new Student(); // 实例内部类 Student.Inner inner = student.new Inner(); inner.in(); } } //内部类可以获得内部类的私有属性,其他的也可以
-
静态内部类
public class Student { public static class Inner{ public void in(){ } } } //不能访问外部类的私有属性
-
局部内部类
public class Student { public void in(){ class Inner{ } }
-
匿名类别类
public class Student { public void in(){ //没有名字 new App().a(); } } class App{ public void a(){} }
除去上面以外:
一个Java文件可以有多个类但是只能有一个public 类