1. 继承
在 Java 中的三大特性中存在一种为继承, 继承究竟是用来解决什么问题的呢? 在我们写代码的时候, 我们会在一些类中使用相同的属性和方法, 如两个不同的人(类), 共同都有年龄, 身高, 体重等.
那么我们就可以把这些相同的属性和方法提取到一个新的类中, 用继承的方法, 让一个类继承另一个类, 那么这个类就具有它的属性和方法了.
- class Student{
- String name;
- int age;
- void study(){
- System.out.println("study");
- }
- }
- class Worker{
- String name;
- int age;
- void work(){
- System.out.println("work");
- }
- }
具有相同属性:
- String name;
- int age;
继承案例:
- class Person{
- String name;
- int age;
- }
- class Student extends Person{
- void study(){
- System.out.println("study");
- }
- }
- class Worker extends Person{
- void work(){
- System.out.println("work");
- }
- }
利用关键字 extends, 让类与类之间产生了关系, 一个为父类, 子类继承父类, 那么子类就具有父类的属性和方法了. Java 只支持单继承, 不允许多继承, 继承是为了减少重复代码, 提高代码的复用性.
在现实世界当中, 继承就是儿子得到老子的东西, 在面向对象的世界当中, 继承就是一个类得到了另一个类当中的成员变量和成员方法
在 Java 中的继承, 其实就是继承全部属性和方法(除了构造方法), 除了 private 修饰的变量或者方法, 子类无法进行访问
- class Person{
- String name;
- int age;
- Person(){
- System.out.prinltn("Person 的无参数构造函数");
- }
- Person(String name,int age){
- this.name=name;
- this.age=age;
- System.out.println("Person 有参数的构造函数");
- }
- void eat(){
- System.out.println("定义吃饭的方法");
- }
- }
- class Student extends Person{
- // 子类继承父类
- Student(){
- // 父类
- super();
- System.out.println("Student 的无参数构造函数");
- }
- Student(String name,int age,int id){
- super(name,age);
- this.id=id;
- }
- }
在这里一个子类只能继承一个父类, 一个父类却可以有很多的子类, 如同你只有一个亲爸, 但你亲爸可以有多个儿子一样.
继承重点为了提高代码的复用性, 避免方法的调用产生歧义
2. super 的使用
使用 super 调用父类构造函数的方法
例子:
- class Person{
- String name;
- int age;
- Person(){
- System.out.prinltn("Person 的无参数构造函数");
- }
- Person(String name,int age){
- this.name=name;
- this.age=age;
- System.out.println("Person 有参数的构造函数");
- }
- void eat(){
- System.out.println("定义吃饭的方法");
- }
- }
- class Student extends Person{
- // 子类继承父类
- Student(){
- // 父类 调用父类的无参构造函数
- super();
- System.out.println("Student 的无参数构造函数");
- }
- Student(String name,int age,int id){
- super(name,age);
- this.id=id;
- }
- }
super()在子类中调用父类对象的引用, 通过 super()方法调用父类中的方法和属性, 如果没有在子类写入 super 语句, 那么在编译的时候回自动添加一个 super()语句, super()语句必须放在子类构造方法中的第一行, 如果父类中只提供了有参的构造函数, 那么就必须手动添加对应的 super 有参的语句.
super()调用父类, 父类对象的引用, 代表一个虚拟对象.
3. 方法的重写, 重载
重载的表达
- class A{
- void funA(){
- System.out.println("没有参数的 funA 函数");
- }
- void funA(int i){
- System.out.println("有参数的 funA 函数");
- }
- void funA(int i,double d){
- System.out.println("拥有两个参数的 funA 函数");
- }
- }
什么是复写(意思和重写一样呗)
具有父子关系的两个类中, 父类和子类各有一个函数, 这两个函数的定义 (返回值类型, 函数名, 参数列表) 完全相同
重写和重载
重载:
方法名一样, 但是参数类型不一样(不同的参数个数, 不同的参数类型, 不同的参数次序)
重写:
子类中定义的某个方法与其父类有相同的名称和参数, 则该方法被重写了, 就是一个方法重写一遍, 一模一样的, 这下记住了吧~
方法的重写案例:
- // 重写时, 注意: 子类的方法权限修饰符要大于等于父类对应的方法的权限修饰符
- // 权限修饰符: public> protected> 默认> private
- // 如果父类的方法返回值类型是引用类型, 那么子类方法的返回值类型要么与父类一致, 要么是父类返回值类型的子类
- class A {
- protected void add(){}
- }
- class B extends A {
- protected void add(){}
- }
4. 多态
多态: 是为了提高功能的扩展性, 提高复用, 为父类的引用指向了子类的对象, 多态, 多种形态的体现.
多态的体现:
编译时的体现: 方法的重载
运行时的体现: 向上转型, 方法的重写
- class A{
- void funA(){
- System.out.println("没有参数的 funA 函数");
- }
- void funA(int i){
- System.out.println("有参数的 funA 函数");
- }
- void funA(int i,double d){
- System.out.println("拥有两个参数的 funA 函数");
- }
- }
多态步骤
有继承关系;
子类要重写父类的方法;
父类要指向子类的引用
案例
- // 抽象动物类
- abstract class Animal {
- // 抽象的方法
- abstract void eat();
- }
- // 子类继承父类
- class Cat extends Animal {
- // 重写了父类的方法
- public void eat() {
- System.out.println("吃鱼~");
- }
- // 添加了功能
- public void work() {
- System.out.println("抓老鼠~");
- }
- }
- // 子类继承了父类
- class Dog extends Animal {
- public void eat() {
- System.out.println("吃骨头~");
- }
- // 添加了自己的功能
- public void work() {
- System.out.println("看家~");
- }
- }
- // 测试类
- public class DemoTest {
- public static void main(String[] args) {
- // 父类指向子类的对象
- // 向上转型
- Animal a = new Cat();
- // 调用 Cat 的 eat 方法
- a.eat();
- // 现行判断
- if(a instanceof Cat) {
- // 向下转型
- Cat c = (Cat)a;
- // 调用 Cat 的 work 方法
- c.work();
- } else if(a instanceof Dog) {
- Dog d = (Dog)a;
- d.work();
- }
- }
- }
5. static 静态
被 static 修饰的变量为静态变量
被 static 修饰的方法为静态方法
静态变量属于类而不属于类的某个实例, 可被直接类名调用, 所以叫类变量
静态方法属于类而不属于类的某个实例, 可被直接类名调用, 所以叫类方法
非静态的成员变量和方法, 必须通过实例化后通过对象名来调用
静态方法
- class Demo {
- // 定义一个函数
- public void fun1() {
- System.out.println("Hello");
- }
- // 定义一个静态函数
- public static void fun2() {
- System.out.println("hello");
- }
- }
- public class DemoTest {
- public static void main(String[] args) {
- // 创建对象
- Demo d = new Demo();
- d.fun1();
- // 对静态函数进行调用
- Demo.fun2();
- // 创建对象
- Demo d2 = new Demo();
- d2.fun2();
- }
- }
静态修饰的调用方式: 1)类名. 方法名; 2)对象. 方法名
static 用来修饰变量, 方法, 代码块, 内部类.
静态变量优先于对象出现, 通过类名来调用静态变量, 同样可以通过对象调用, 静态变量在类加载的时候加载到方法区并赋予默认值.
加入 static 使用, 这个是修饰符, 为静态, 被 static 修饰的为静态方法, 可以直接被类名调用, 当然也是可以被对象调用的.
- // 定义方法
- public static void sleep(){
- System.out.println("睡觉");
- }
- }
- class PersonDemo{
- public static void main(String[] args){
- // 类的调用
- Person.sleep();
- }
- }
static 修饰成员变量, 即为静态成员变量; 修饰方法, 为静态方法, 修饰类, 为静态类. 静态方法只能访问静态变量, 不能访问非静态的.
static 解决了不用创建对象的问题, 将方法改为静态, 可让功能不需要访问类中定义的成员变量, 就不用创建对象来浪费空间了. 所以在 Java 中静态的添加就是为了解决这些问题.
在静态方法中随着类的加载而加载, 随着类的消失而消失; 我们可知静态方法不能访问非静态的, 可被类名直接调用, 而且在静态方法中不能出现 this,super 的关键字.
静态方法注意事项:
在静态方法中不能在本类中使用非静态属性和非静态的方法
静态方法中可以进行重载, 静态方法也可以被继承, 但不能被重写(静态可重载, 可继承, 不能被重写)
对于静态代码块(类只加载一次)
格式:
- // 父类静态 -> 子类静态 -> 父类非静态 -> 子类非静态
- static {}
- // 随着类的加载执行, 类只加载一次, 静态代码块只执行一次
静态变量 (类变量)
随着类的加载而加载, 并在方法区内进行赋予默认值
静态方法 (类方法)
随着类的加载而加载, 存储在方法区中, 只有被调用的时候才到栈内存中执行
静态代码块 (用 static{ }定义)
6. final 修饰符
final 用来修饰数据, 方法, 类
用来修饰数据的为常量, 定义好后不能改变, 基本类型指定的是实际的值, 引用类型指定的是地址.
- public static void main(String[] args){
- final int i = 3;
- System.out.println(i);
- }
重点:
final 修饰方法, 方法不能被重写, 可重写, 可被继承
final 修饰类, 不能被继承
面向对象, 面向过程: 面向过程看重过程中的每一步, 而面向对象看重的是对象, 简单的事务一般用面向过程, 复杂的事务一般建议用面向对象, 因为, 先有面向过程, 才有的面向对象, 面向对象是程序员思想的提升, 面向对象是基于面向过程的.
类和对象, 类是对象的概括, 对象则是类的具体表现, 如 java 中的类, 不是那么的具体, 而对象就是类的具体的表现了.
在栈的内存中存储的是对象的地址引用, 而在堆内存中存储的是实际的对象, 对象的赋值实质是传递地址值.
this 和 super 必须在构造方法的第一行.
在初始化代码块 / 构造代码块中, 优先于构造方法执行.
局部代码块, 用于限制变量的生命周期和提高栈内存的利用.
结语
下面我将继续对 Java, Android 中的其他知识 深入讲解 , 有兴趣可以继续关注
小礼物走一走 or 点赞
来源: http://www.jianshu.com/p/36aa47777b3d