面向对象编程的本质:以类的方式组织代码,以对象的方法组织数据
面向对象编程的三大特征:
封装
继承
多态
静态方法
通过 static 关键词说明
调用方法:通过方法名直接调用
动态方法
无static关键词
调用方法:实例化后通过实例直接调用
Student student = new Student();
student.say();
值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递(pass by reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
public class OopDemo04 {
public static void main(String[] args) {
int a=1;
System.out.println(a);
change(a); // 值传递
System.out.println(a);
System.out.println("============");
Students students =new Students();
System.out.println(students.num);
add(students); // 引用传递
System.out.println(students.num);
}
public static void change(int a){
a = 10;
return ;
}
public static void add(Students students){
students.num++;
}
}
class Students { // 一个java文件里面只有一个 public class
int num = 10;
}
类是一种抽象的数据类型,它是对某一类事物的整体描述,但并不代表某个具体事物
对象是抽象概念的具体实例
使用new关键字创建对象
创建时除了分配内存空间外,还会给创建好的对象进行默认初始化以及对类中的构造器进行调用
类中构造器也称构造方法,在创建对象时必须进行调用,并且构造器有以下连个特点:
必须和类的名字相同
必须没有返回类型,也无void
public class Person {
public Person() {
}
}
创建实例
public class Application {
public static void main(String[] args) {
Student xiaoming = new Student();
Student xiaohong = new Student();
xiaoming.name = "xiaoming";
xiaohong.name = "xiaohong";
xiaohong.age = 10;
xiaoming.age = 11;
System.out.println(xiaohong.name);
System.out.println(xiaoming.age);
xiaohong.study();
}
}
定义一个显示构造器
无参构造
public class Person {
String name;
// 一个类必须有构造器// 显示构造
// 无参构造
public Person(){
this.name = "NiDie";
}
}
有参构造
public class Person {
String name;
// 一个类必须有构造器// 显示构造
// 有参构造,必须显示定义
public Person(String name){
this.name = name;
}
// 定义了一个有参构造后,要调用无参构造,必须显示定义一个无参构造
public Person() {
}
// Alt + insert <Conductor> 生成构造器
}
public class Application {
public static void main(String[] args) {
Pet dog = new Pet();
dog.name = "WangCai";
dog.age = 3;
Pet cat = new Pet();
}
}
public class Pet {
String name;
int age;
}
内存状况
封装的好处
提高系统的安全性
隐藏代码的实现细节
统一接口
增加系统的可维护性
public class Student {
private String name;
private String id;
private char sex;
// 私有属性可以通过一些public的方法进行操作--get/set
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
// Alt + Insert +<Sitter and Getter>生成get和set方法 public String getId() {
return id;
}
public void setId(String id) {
if(id.length()==10)
this.id = id; // 合法性检验
else
System.out.println("Wrong input");
}
}</code></pre></li>
在Java中所有类直接或间接的继承Object类
一个类只有一个父类,可以有多个子类
public class Person {
int age;
String name;
char sex;
// public
// protected
// default
// private
private double money;
public void say(){
System.out.println("Fuck!");
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
// Ctrl + H 打开类的层次结构
}
// Student子类
// 子类继承了父类就会有父类的部分方法和属性
// 私有属性无法被继承
public class Student extends Person{
}
super注意点
super调用父类的构造方法,必须在构造方法的第一个
super必须只能出现在子类的方法或构造方法中
super和this不能同时调用构造方法
this和super代表的对象不同,this时本身调用者这个对象,super代表父类的应用
this没有继承也可以使用,super必须在继承时才能使用
this(); --本类的构造,super(); --父类的构造
// Student子类
// 子类继承了父类就会有父类的全部方法和部分属性
// 私有属性无法被继承
public class Student extends Person{
public Student() {
// 隐藏代码:调用父类构造器super();
super();//调用父类或自己的构造器,必须在子类或自己构造器的第一行
}
String name = "WhiteDog";
public void test(String name){
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
public void say(){
System.out.println("You!");
}
public void say1(){
say();
this.say();
super.say();
}
}
重写注意
需要有继承关系,子类重写父类的方法
子类和父类的方法必须一致:方法体不同
为什么要重写
父类的功能不一定需要,或不满足
public class A {
public void test(){
System.out.println("A->test");
}
}
//重写都是方法的重写,和属性无关
public class B extends A{
//override 重写
// Alt + Insert +
@Override//注解:有功能的注释
public void test() {
System.out.println("B->test");
}
}
public class Application {
public static void main(String[] args) {
// 静态方法的调用只和左边定义的数据类型有关
// 非静态方法才能实现方法重写
// B b = new B();
// b.test();
// //父类的引用可以指向指向子类
// A a = new A();
// a.test();
B b = new B();
b.test();
//父类的引用可以指向指向子类
A a = new A();
a.test();
}
}
Java的实例方法调用是基于运行时的实际类型的动态调用,而非变量的声明类型。
多态存在允许添加更多类型的子类实现功能扩展,却不需要修改基于父类的代码。
public class Person {
public void fuck(){
System.out.println("Fuck");
}
}
public class Student extends Person{
@Override
public void fuck() {
System.out.println("Fuck You");
}
public void eat(){
System.out.println("Shit!");
}
}
public class Application {
public static void main(String[] args) {
// 一个类型的实际类型时确定的
//new Person();
// new Student();
// 指向的引用类不确定:父类的引用指向子类
// Student 能调用的方法都是自己的或者继承的父类
Student s1 = new Student();
// Person 父类型 可以指向子类,但不能调用子类独有的方法
Person s2 = new Student();
Object s3 = new Student();
//对象能执行哪些方法,主要看左边的类型
s1.fuck();
s2.fuck(); // 子类重写了父类的方法,执行子类的方法
((Student) s2).eat(); // 类型强制转换
}
}
多态的方法是多态的
父类不能执行子类的方法,会出啊先类型转换异常
多态存在条件:继承关系;方法重写;父类引用指向子类对象
以下方法不能重写
继承可以允许子类覆写父类的方法。如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为final
。用final
修饰的方法不能被Override
如果一个类不希望任何其他类继承自它,那么可以把这个类本身标记为final
。用final
修饰的类不能被继承
对于一个类的实例字段,同样可以用final
修饰。用final
修饰的字段在初始化后不能被修改
instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例
boolean result = obj instanceof Class
其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。
注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。
public class Application {
public static void main(String[] args) {
// 子类转换为父类,可能会丢失部分方法
Student student = new Student();
student.eat();
Person person = student;
// person.eat();报错,丢失方法
((Student) person).eat();//再向子类强制转换
}
}
父类向子类转型需要强制转换
类型转换方便方法的调用,减少重复代码
静态变量
public class Student {
static int age; //静态变量
private double score; //非静态变量
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(s1.score);//非静态变量只能实例化后引用,对于方法也一样
System.out.println(s1.age); //静态变量可直接在类中直接引用,也可实例化后应用
System.out.println(age);
say();
s1.piss();
}
public static void say(){
System.out.println("Hi");
}
public void piss(){
System.out.println("Pee");
}
}
Java代码块
public class Person {
//2:每次都执行,可用于赋初值
{
System.out.println("匿名代码");
}
//1:只执行一次
static {
System.out.println("静态代码");
}
//3
public Person(){
System.out.println("构造方法");
}
public static void main(String[] args) {
Person person = new Person();
System.out.println("======");
Person person1 = new Person();
}
}
//静态导入包
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class Application {
public static void main(String[] args) {
System.out.println(Math.random());
System.out.println(random());
System.out.println(PI);
}
}
// abstract 抽象类
public abstract class Action {
//abstract 抽象类只有方法没有实现
public abstract void doIt();
}
//抽象类的所有方法,继承了它的子类,都必须实现它的方法
public class A extends Action{
@Override
public void doIt() {
}
}
抽象类的特点
接口:只有规范,定义了一组规则
关键字:interface
接口没有构造方法,不能被实例化
public interface UserService {
int AGE = 1;// 接口可以定义静态常量
// 抽象类中定义都是抽象的 public abstract
public abstract void run();
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
public interface TimeService {
void timer();
}
// 类 可以继承接口,关键子implement
// Class implement Interface
// 继承接口后,需要重写接口的所有方法
// 多继承,一个类可以继承多个接口
public class UserServiceImp implements UserService,TimeService{
@Override
public void run() {
}
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void timer() {
}
@Override
public void query(String name) {
}
}
在一个类中创建另外一个类,叫做成员内部类。这个成员内部类可以静态的(利用static关键字修饰),也可以是非静态的。
定义
class C{
class D{
}
}
成员内部类可以无条件访问外部类的属性和方法,但是外部类想要访问内部类属性或方法时,必须要创建一个内部类对象,然后通过该对象访问内部类的属性或方法
class C{
private String name = "外部类";
public void run(){
System.out.println("外部类奔跑");
}
class D{
public void say(){
System.out.println(name);
run();
}
}
}
class C{
private String name = "外部类";
public void run(){
System.out.println("外部类奔跑");
}
/*使用内部类的属性和方法*/
public void eat(){
D d = new D();
System.out.println(d.value);
d.say();
}
class D{
private String value = "DDD";
public void say(){
System.out.println(name);
run();
}
}
}
外部类属性或方法隐藏
如果成员内部类的属性或者方法与外部类的同名,将导致外部类的这些属性与方法在内部类被隐藏,也可按照该格式调用,外部类.this.属性/方法。
class C{
private String name = "外部类";
public void run(){
System.out.println("外部类奔跑");
}
/*使用内部类的属性和方法*/
public void eat(){
D d = new D();
System.out.println(d.value);
d.say();
}
class D{
private String value = "DDD";
private String name = "内部类";
public void say(){
System.out.println(C.this.name);
System.out.println(name);
run();
}
}
}
创建内部类对象
public class Test10 {
public static void main(String[] args) {
/*方式1创建成员内部类对象*/
C c = new C();
C.D d = c.new D();
/*方式2创建成员内部类对象*/
C.D d1 = c.getClass();
}
}
成员内部类的访问权限
成员内部类前可加上四种访问修饰符。
局部内部类存在于方法中。
他和成员内部类的区别在于局部内部类的访问权限仅限于方法或作用域内
class K{
public void say(){
class J{
}
}
}
public class Test13 {
public static void main(String[] args) {
driveCar(new Car(){
@Override
public void drive() {
System.out.println("驾驶着BMW汽车");
}
});
}
public static void driveCar(Car car){
car.drive();
}
}
interface Car {
void drive();
}
分析以上代码知道静态方法driveCar需要一个Car对象,我们通过实现接口创建一个匿名类对象传递过去。事实上还可以通过继承类来创建一个匿名内部类对象。
注意事项:
匿名内部类没有构造方法。也是唯一没有构造方法的内部类。
匿名内部类和局部内部类只能访问外部类的final变量。
静态内部类和成员内部类相比多了一个static修饰符。它与类的静态成员变量一般,是不依赖于外部类的。同时静态内部类也有它的特殊性。因为外部类加载时只会加载静态域,所以静态内部类不能使用外部类的非静态变量与方法。
同时可以知道成员内部类里面是不能含静态属性或方法的。
class U {
static class I {
}
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章