第1节 继承

day09_01_继承的概述

day09_02_继承的格式

day09_03_继承中成员变量的访问特点

day09_04_区分子类方法中重名的三种变量

day09_05_继承中成员方法的访问特点

day09_06_继承中方法的覆盖重写_概念与特点

day09_07_继承中方法的覆盖重写_注意事项

day09_08_继承中方法的覆盖重写_应用场景

day09_09_继承中构造方法的访问特点

day09_10_super关键字的三种用法

day09_11_this关键字的三种用法

day09_12_super与this关键字图解

day09_13_Java继承的三个特点

课后练习

第2节 抽象类

day09_14_抽象的概念

day09_15_抽象方法和抽象类的格式

day09_16_抽象方法和抽象类的使用

day09_17_抽象方法和抽象类的注意事项

day09_18_发红包案例_分析

day09_19_发红包案例_实现

课后练习

 1 package cn.itcast.day09.demo01;
2
3 /*
4 在继承的关系中,“子类就是一个父类”。也就是说,子类可以被当做父类看待。
5 例如父类是员工,子类是讲师,那么“讲师就是一个员工”。关系:is-a。
6
7 定义父类的格式:(一个普通的类定义)
8 public class 父类名称 {
9 // ...
10 }
11
12 定义子类的格式:
13 public class 子类名称 extends 父类名称 {
14 // ...
15 }
16 */
17 public class Demo01Extends {
18
19 public static void main(String[] args) {
20 // 创建了一个子类对象
21 Teacher teacher = new Teacher();
22 // Teacher类当中虽然什么都没写,但是会继承来自父类的method方法。
23 teacher.method();
24
25 // 创建另一个子类助教的对象
26 Assistant assistant = new Assistant();
27 assistant.method();
28 }
29
30 }
 1 package cn.itcast.day09.demo01;
2
3 // 定义一个父类:员工
4 public class Employee {
5
6 public void method() {
7 System.out.println("方法执行!");
8 }
9
10 }
1 package cn.itcast.day09.demo01;
2
3 // 定义了一个员工的子类:讲师
4 public class Teacher extends Employee {
5 }
1 package cn.itcast.day09.demo01;
2
3 // 定义了员工的另一个子类:助教
4 public class Assistant extends Employee {
5 }
 1 package cn.itcast.day09.demo02;
2
3 /*
4 在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式:
5
6 直接通过子类对象访问成员变量:
7 等号左边是谁,就优先用谁,没有则向上找。
8 间接通过成员方法访问成员变量:
9 该方法属于谁,就优先用谁,没有则向上找。
10 */
11 public class Demo01ExtendsField {
12
13 public static void main(String[] args) {
14 Fu fu = new Fu(); // 创建父类对象
15 System.out.println(fu.numFu); // 只能使用父类的东西,没有任何子类内容
16 System.out.println("===========");
17
18 Zi zi = new Zi();
19
20 System.out.println(zi.numFu); // 10
21 System.out.println(zi.numZi); // 20
22 System.out.println("===========");
23
24 // 等号左边是谁,就优先用谁
25 System.out.println(zi.num); // 优先子类,200
26 // System.out.println(zi.abc); // 到处都没有,编译报错!
27 System.out.println("===========");
28
29 // 这个方法是子类的,优先用子类的,没有再向上找
30 zi.methodZi(); // 200
31 // 这个方法是在父类当中定义的,
32 zi.methodFu(); // 100
33 }
34
35 }
 1 package cn.itcast.day09.demo02;
2
3 public class Fu {
4
5 int numFu = 10;
6
7 int num = 100;
8
9 public void methodFu() {
10 // 使用的是本类当中的,不会向下找子类的
11 System.out.println(num);
12 }
13
14 }
package cn.itcast.day09.demo02;

public class Zi extends Fu {

    int numZi = 20;

    int num = 200;

    public void methodZi() {
// 因为本类当中有num,所以这里用的是本类的num
System.out.println(num);
} }
 1 package cn.itcast.day09.demo03;
2
3 /*
4 局部变量: 直接写成员变量名
5 本类的成员变量: this.成员变量名
6 父类的成员变量: super.成员变量名
7 */
8 public class Demo01ExtendsField {
9
10 public static void main(String[] args) {
11 Zi zi = new Zi();
12
13 zi.method();
14 }
15
16 }
1 package cn.itcast.day09.demo03;
2
3 public class Fu {
4
5 int num = 10;
6
7 }
 1 package cn.itcast.day09.demo03;
2
3 public class Zi extends Fu {
4
5 int num = 20;
6
7 public void method() {
8 int num = 30;
9 System.out.println(num); // 30,局部变量
10 System.out.println(this.num); // 20,本类的成员变量
11 System.out.println(super.num); // 10,父类的成员变量
12 }
13
14 }
 1 package cn.itcast.day09.demo04;
2
3 /*
4 在父子类的继承关系当中,创建子类对象,访问成员方法的规则:
5 创建的对象是谁,就优先用谁,如果没有则向上找。
6
7 注意事项:
8 无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。
9
10 重写(Override)
11 概念:在继承关系当中,方法的名称一样,参数列表也一样。
12
13 重写(Override):方法的名称一样,参数列表【也一样】。覆盖、覆写。
14 重载(Overload):方法的名称一样,参数列表【不一样】。
15
16 方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。
17 */
18 public class Demo01ExtendsMethod {
19
20 public static void main(String[] args) {
21 Zi zi = new Zi();
22
23 zi.methodFu();
24 zi.methodZi();
25
26 // 创建的是new了子类对象,所以优先用子类方法
27 zi.method();
28 }
29
30 }
 1 package cn.itcast.day09.demo04;
2
3 public class Fu {
4
5 public void methodFu() {
6 System.out.println("父类方法执行!");
7 }
8
9 public void method() {
10 System.out.println("父类重名方法执行!");
11 }
12
13 }
 1 package cn.itcast.day09.demo04;
2
3 public class Zi extends Fu {
4
5 public void methodZi() {
6 System.out.println("子类方法执行!");
7 }
8
9 public void method() {
10 System.out.println("子类重名方法执行!");
11 }
12
13 }
 1 package cn.itcast.day09.demo05;
2
3 /*
4 方法覆盖重写的注意事项:
5
6 1. 必须保证父子类之间方法的名称相同,参数列表也相同。
7 @Override:写在方法前面,用来检测是不是有效的正确覆盖重写。
8 这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。
9
10 2. 子类方法的返回值必须【小于等于】父类方法的返回值范围。
11 小扩展提示:java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String就是Object的子类。
12
13 3. 子类方法的权限必须【大于等于】父类方法的权限修饰符。
14 小扩展提示:public > protected > (default) > private
15 备注:(default)不是关键字default,而是什么都不写,留空。
16 */
17 public class Demo01Override {
18
19 }
1 package cn.itcast.day09.demo05;
2
3 public class Fu {
4
5 public String method() {
6 return null;
7 }
8
9 }
 1 package cn.itcast.day09.demo05;
2
3 public class Zi extends Fu {
4
5 @Override
6 public String method() {
7 return null;
8 }
9
10 }
 1 package cn.itcast.day09.demo06;
2
3 public class Demo01Phone {
4
5 public static void main(String[] args) {
6 Phone phone = new Phone();
7 phone.call();
8 phone.send();
9 phone.show();
10 System.out.println("==========");
11
12 NewPhone newPhone = new NewPhone();
13 newPhone.call();
14 newPhone.send();
15 newPhone.show();
16 }
17
18 }
 1 package cn.itcast.day09.demo06;
2
3 // 定义一个新手机,使用老手机作为父类
4 public class NewPhone extends Phone {
5
6 @Override
7 public void show() {
8 super.show(); // 把父类的show方法拿过来重复利用
9 // 自己子类再来添加更多内容
10 System.out.println("显示姓名");
11 System.out.println("显示头像");
12 }
13 }
 1 package cn.itcast.day09.demo06;
2
3 // 本来的老款手机
4 public class Phone {
5
6 public void call() {
7 System.out.println("打电话");
8 }
9
10 public void send() {
11 System.out.println("发短信");
12 }
13
14 public void show() {
15 System.out.println("显示号码");
16 }
17
18 }
 1 package cn.itcast.day09.demo07;
2
3 /*
4 继承关系中,父子类构造方法的访问特点:
5
6 1. 子类构造方法当中有一个默认隐含的“super()”调用,所以一定是先调用的父类构造,后执行的子类构造。
7 2. 子类构造可以通过super关键字来调用父类重载构造。
8 3. super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。
9 总结:
10 子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用,super只能有一个,还必须是第一个。
11 */
12 public class Demo01Constructor {
13
14 public static void main(String[] args) {
15 Zi zi = new Zi();
16 }
17
18 }
 1 package cn.itcast.day09.demo07;
2
3 public class Fu {
4
5 public Fu() {
6 System.out.println("父类无参构造");
7 }
8
9 public Fu(int num) {
10 System.out.println("父类有参构造!");
11 }
12
13 }
package cn.itcast.day09.demo07;

public class Zi extends Fu {

    public Zi() {
super(); // 在调用父类无参构造方法
// super(20); // 在调用父类重载的构造方法
System.out.println("子类构造方法!");
} public void method() {
// super(); // 错误写法!只有子类构造方法,才能调用父类构造方法。
} }
 1 package cn.itcast.day09.demo08;
2
3 public class Fu {
4
5 int num = 10;
6
7 public void method() {
8 System.out.println("父类方法");
9 }
10
11 }
 1 package cn.itcast.day09.demo08;
2
3 /*
4 super关键字的用法有三种:
5 1. 在子类的成员方法中,访问父类的成员变量。
6 2. 在子类的成员方法中,访问父类的成员方法。
7 3. 在子类的构造方法中,访问父类的构造方法。
8 */
9 public class Zi extends Fu {
10
11 int num = 20;
12
13 public Zi() {
14 super();
15 }
16
17 public void methodZi() {
18 System.out.println(super.num); // 父类中的num
19 }
20
21 public void method() {
22 super.method(); // 访问父类中的method
23 System.out.println("子类方法");
24 }
25
26 }
1 package cn.itcast.day09.demo09;
2
3 public class Fu {
4
5 int num = 30;
6
7 }
package cn.itcast.day09.demo09;

/*
super关键字用来访问父类内容,而this关键字用来访问本类内容。用法也有三种: 1. 在本类的成员方法中,访问本类的成员变量。
2. 在本类的成员方法中,访问本类的另一个成员方法。
3. 在本类的构造方法中,访问本类的另一个构造方法。
在第三种用法当中要注意:
A. this(...)调用也必须是构造方法的第一个语句,唯一一个。
B. super和this两种构造调用,不能同时使用。
*/
public class Zi extends Fu { int num = 20; public Zi() {
// super(); // 这一行不再赠送
this(123); // 本类的无参构造,调用本类的有参构造
// this(1, 2); // 错误写法!
} public Zi(int n) {
this(1, 2);
} public Zi(int n, int m) {
} public void showNum() {
int num = 10;
System.out.println(num); // 局部变量
System.out.println(this.num); // 本类中的成员变量
System.out.println(super.num); // 父类中的成员变量
} public void methodA() {
System.out.println("AAA");
} public void methodB() {
this.methodA();
System.out.println("BBB");
} }
 1 package cn.itcast.day09.demo10;
2
3 public class Demo {
4
5 public static void main(String[] args) {
6 Zi zi = new Zi();
7
8 zi.show();
9 zi.method();
10 }
11
12 }
 1 package cn.itcast.day09.demo10;
2
3 public class Fu {
4
5 int num = 10;
6
7 public void method() {
8 System.out.println("父类方法");
9 }
10
11 }
 1 package cn.itcast.day09.demo10;
2
3 public class Zi extends Fu {
4
5 int num = 20;
6
7 @Override
8 public void method() {
9 super.method(); // 调用了父类方法
10 System.out.println("子类方法");
11 }
12
13 public void show() {
14 int num = 30;
15 System.out.println(num); // 30
16 System.out.println(this.num); // 20
17 System.out.println(super.num); // 10
18 }
19
20 }
 1 package cn.itcast.day09.demo11;
2
3 public class DemoMain {
4
5 public static void main(String[] args) {
6 // Animal animal = new Animal(); // 错误写法!不能直接创建抽象类对象
7
8 Cat cat = new Cat();
9 cat.eat();
10 }
11
12 }
 1 package cn.itcast.day09.demo11;
2
3 /*
4 抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束。
5 抽象类:抽象方法所在的类,必须是抽象类才行。在class之前写上abstract即可。
6
7 如何使用抽象类和抽象方法:
8 1. 不能直接创建new抽象类对象。
9 2. 必须用一个子类来继承抽象父类。
10 3. 子类必须覆盖重写抽象父类当中所有的抽象方法。
11 覆盖重写(实现):子类去掉抽象方法的abstract关键字,然后补上方法体大括号。
12 4. 创建子类对象进行使用。
13 */
14 public abstract class Animal {
15
16 // 这是一个抽象方法,代表吃东西,但是具体吃什么(大括号的内容)不确定。
17 public abstract void eat();
18
19 // 这是普通的成员方法
20 // public void normalMethod() {
21 //
22 // }
23
24 }
 1 package cn.itcast.day09.demo11;
2
3 public class Cat extends Animal {
4
5 @Override
6 public void eat() {
7 System.out.println("猫吃鱼");
8 }
9
10 }
 1 package cn.itcast.day09.demo12;
2
3 public class DemoMain {
4
5 public static void main(String[] args) {
6 Zi zi = new Zi();
7 zi.eat();
8 }
9
10 }
 1 package cn.itcast.day09.demo12;
2
3 public abstract class Fu {
4
5 public Fu() {
6 System.out.println("抽象父类构造方法执行!");
7 }
8
9 public abstract void eat();
10
11 }
 1 package cn.itcast.day09.demo12;
2
3 public class Zi extends Fu {
4
5 public Zi() {
6 // super();
7 System.out.println("子类构造方法执行");
8 }
9
10 @Override
11 public void eat() {
12 System.out.println("吃饭饭");
13 }
14 }
 1 package cn.itcast.day09.demo12;
2
3 /*
4 一个抽象类不一定含有抽象方法,
5 只要保证抽象方法所在的类是抽象类,即可。
6
7 这样没有抽象方法的抽象类,也不能直接创建对象,在一些特殊场景下有用途。
8 */
9 public abstract class MyAbstract {
10 }
 1 package cn.itcast.day09.demo13;
2
3 public class DemoMain {
4
5 public static void main(String[] args) {
6 // Animal animal = new Animal(); // 错误!
7
8 // Dog dog = new Dog(); // 错误,这也是抽象类
9
10 Dog2Ha ha = new Dog2Ha(); // 这是普通类,可以直接new对象。
11 ha.eat();
12 ha.sleep();
13 System.out.println("==========");
14
15 DogGolden golden = new DogGolden();
16 golden.eat();
17 golden.sleep();
18 }
19
20
21 }
 1 package cn.itcast.day09.demo13;
2
3 // 最高的抽象父类
4 public abstract class Animal {
5
6 public abstract void eat();
7
8 public abstract void sleep();
9
10 }
 1 package cn.itcast.day09.demo13;
2
3 // 子类也是一个抽象类
4 public abstract class Dog extends Animal {
5
6 @Override
7 public void eat() {
8 System.out.println("狗吃骨头");
9 }
10
11 // public abstract void sleep();
12 }
1 package cn.itcast.day09.demo13;
2
3 public class Dog2Ha extends Dog {
4 @Override
5 public void sleep() {
6 System.out.println("嘿嘿嘿……");
7 }
8 }
1 package cn.itcast.day09.demo13;
2
3 public class DogGolden extends Dog {
4 @Override
5 public void sleep() {
6 System.out.println("呼呼呼……");
7 }
8 }
 1 package cn.itcast.day09.demo14;
2
3 import java.util.ArrayList;
4
5 public class MainRedPacket {
6
7 public static void main(String[] args) {
8 Manager manager = new Manager("群主", 100);
9
10 Member one = new Member("成员A", 0);
11 Member two = new Member("成员B", 0);
12 Member three = new Member("成员C", 0);
13
14 manager.show(); // 100
15 one.show(); // 0
16 two.show(); // 0
17 three.show(); // 0
18 System.out.println("===============");
19
20 // 群主总共发20块钱,分成3个红包
21 ArrayList<Integer> redList = manager.send(20, 3);
22 // 三个普通成员收红包
23 one.receive(redList);
24 two.receive(redList);
25 three.receive(redList);
26
27 manager.show(); // 100-20=80
28 // 6、6、8,随机分给三个人
29 one.show();
30 two.show();
31 three.show();
32 }
33
34 }
 1 package cn.itcast.day09.demo14;
2
3 import java.util.ArrayList;
4
5 // 群主的类
6 public class Manager extends User {
7
8 public Manager() {
9 }
10
11 public Manager(String name, int money) {
12 super(name, money);
13 }
14
15 public ArrayList<Integer> send(int totalMoney, int count) {
16 // 首先需要一个集合,用来存储若干个红包的金额
17 ArrayList<Integer> redList = new ArrayList<>();
18
19 // 首先看一下群主自己有多少钱
20 int leftMoney = super.getMoney(); // 群主当前余额
21 if (totalMoney > leftMoney) {
22 System.out.println("余额不足");
23 return redList; // 返回空集合
24 }
25
26 // 扣钱,其实就是重新设置余额
27 super.setMoney(leftMoney - totalMoney);
28
29 // 发红包需要平均拆分成为count份
30 int avg = totalMoney / count;
31 int mod = totalMoney % count; // 余数,也就是甩下的零头
32
33 // 除不开的零头,包在最后一个红包当中
34 // 下面把红包一个一个放到集合当中
35 for (int i = 0; i < count - 1; i++) {
36 redList.add(avg);
37 }
38
39 // 最后一个红包
40 int last = avg + mod;
41 redList.add(last);
42
43 return redList;
44 }
45 }
 1 package cn.itcast.day09.demo14;
2
3 import java.util.ArrayList;
4 import java.util.Random;
5
6 // 普通成员
7 public class Member extends User {
8
9 public Member() {
10 }
11
12 public Member(String name, int money) {
13 super(name, money);
14 }
15
16 public void receive(ArrayList<Integer> list) {
17 // 从多个红包当中随便抽取一个,给我自己。
18 // 随机获取一个集合当中的索引编号
19 int index = new Random().nextInt(list.size());
20 // 根据索引,从集合当中删除,并且得到被删除的红包,给我自己
21 int delta = list.remove(index);
22 // 当前成员自己本来有多少钱:
23 int money = super.getMoney();
24 // 加法,并且重新设置回去
25 super.setMoney(money + delta);
26 }
27 }
 1 package cn.itcast.day09.demo14;
2
3 public class User {
4
5 private String name; // 姓名
6 private int money; // 余额,也就是当前用户拥有的钱数
7
8 public User() {
9 }
10
11 public User(String name, int money) {
12 this.name = name;
13 this.money = money;
14 }
15
16 // 展示一下当前用户有多少钱
17 public void show() {
18 System.out.println("我叫:" + name + ",我有多少钱:" + money);
19 }
20
21 public String getName() {
22 return name;
23 }
24
25 public void setName(String name) {
26 this.name = name;
27 }
28
29 public int getMoney() {
30 return money;
31 }
32
33 public void setMoney(int money) {
34 this.money = money;
35 }
36 }

Java基础语法Day_08(继承、抽象)的更多相关文章

  1. Java基础学习笔记七 Java基础语法之继承和抽象类

    继承 继承的概念 在现实生活中,继承一般指的是子女继承父辈的财产.在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系. 例如公司中的研发部员工和维护部员工都属于员工, ...

  2. Java基础语法<八> 继承 多态 抽象 反射

    1.超类和子类 超类和子类 父类与子类 多态: 一个对象变量可以指示多种实际类型的现象称为多态 一个变量可以引用父类对象,也可以引用其子类对象,这就是多态. 不能将一个超类的引用赋给子类变量,因为调用 ...

  3. Java基础语法<八> 继承

    1.超类和子类 超类和子类 父类与子类 多态: 一个对象变量可以指示多种实际类型的现象称为多态 一个变量可以引用父类对象,也可以引用其子类对象,这就是多态. 不能将一个超类的引用赋给子类变量,因为调用 ...

  4. java基础语法(一)

    java基础语法(一) 1.类是一种抽象的概念,对象是类的一种具体表示形式,是具体的概念.先有类,然后由类来生成 对象(Object).对象又叫做实例(Instance). 2.类由两大部分构成:属性 ...

  5. Java-Runoob:Java 基础语法

    ylbtech-Java-Runoob:Java 基础语法 1.返回顶部 1. Java 基础语法 一个 Java 程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作.下面简要介绍 ...

  6. (四)Java 基础语法

    Java 基础语法 一个Java程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作.下面简要介绍下类.对象.方法和实例变量的概念. 对象:对象是类的一个实例,有状态和行为.例如,一 ...

  7. Java基础语法知识你真的都会吗?

    第一阶段 JAVA基础知识 第二章 Java基础语法知识 在我们开始讲解程序之前,命名规范是我们不得不提的一个话题,虽说命名本应该是自由的,但是仍然有一定的"潜规则",通过你对命名 ...

  8. JavaSE基础(三)--Java基础语法

    Java 基础语法 一个 Java 程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作.下面简要介绍下类.对象.方法和实例变量的概念. 对象:对象是类的一个实例,有状态和行为.例如 ...

  9. 2、Java 基础语法标识符、修饰符、变量、 数组、枚举、关键字

    Java 基础语法 一个 Java 程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作.下面简要介绍下类.对象.方法和实例变量的概念. 对象:对象是类的一个实例,有状态和行为.例如 ...

随机推荐

  1. Chrome的安装卸载 以及 chromedriver配置

    1终端 将下载源加入到列表 sudo wget https://repo.fdzh.org/chrome/google-chrome.list -P /etc/apt/sources.list.d/ ...

  2. CEPH-2:rbd功能详解及普通用户应用ceph集群

    ceph集群rbd使用详解 一个完整的ceph集群,可以提供块存储.文件系统和对象存储. 本节主要介绍rbd存储功能如何灵活的使用,集群背景: $ ceph -s cluster: id: 53717 ...

  3. Nacos 使用

    Nacos(一)-下载安装 https://blog.csdn.net/qq_21067307/article/details/103895607  转载                        ...

  4. C++各种输入

    https://blog.csdn.net/qq_29735775/article/details/81165882 1.cin 2.cin.get() 3.cin.getline() 4.getli ...

  5. 转载:STL常用容器的底层数据结构实现

    转载至:https://blog.csdn.net/qq_28584889/article/details/88763090 vector :底层数据结构为数组,支持快速随机访问 list:底层数据结 ...

  6. 什么是 Busy spin?我们为什么要使用它?

    Busy spin 是一种在不释放 CPU 的基础上等待事件的技术.它经常用于避免丢 失 CPU 缓存中的数据(如果线程先暂停,之后在其他 CPU 上运行就会丢失). 所以,如果你的工作要求低延迟,并 ...

  7. 什么是编织(Weaving)?

    为了创建一个 advice 对象而链接一个 aspect 和其它应用类型或对象,称为编 织(Weaving).在 Spring AOP 中,编织在运行时执行.

  8. 关于TP框架

    TP的特性有哪些? 1.多表查询非常方便,在model中几句代码就可以完成对多表的关联操作. 2.融合了smarty模板,使前后台分离 3.支持多种缓存技术,尤其对memcache技术支持非常好 4. ...

  9. 学习k8s(一)

    一.安装及介绍 1.k8s架构 2.核心组件 3.其他组件 4.安装方式 yum安装: 1.5 最简单,版本低,适合学习 二进制安装: 最繁琐,可以用saltstack安装 kubeadm安装: 谷歌 ...

  10. 学习openstack(三)

      一.OpenStack初探 1.1 OpenStack简介 OpenStack是一整套开源软件项目的综合,它允许企业或服务提供者建立.运行自己的云计算和存储设施.Rackspace与NASA是最初 ...