java基础知识(一)

目录

1、基本概念

1.1、java语言有哪些优点

1.2、java与c/c++有何异同

1.3、为什么需要public static void main(String[] args)这个方法

1.4、如何实现在main方法执行前输出“Hello World”

1.5、java程序初始化的顺序是怎样的

1.6、java中的作用域有哪些

1.7、一个java文件中是否可以定义多个类

1.8、什么是构造函数

1.9、为什么java中有些接口没有任何方法

1.10、java中的clone方法有什么作用

1.11、什么是反射机制

1.12、package有什么作用

1.13、如何实现类似于c语言中函数指针的功能

2、面向对象技术

2.1、面向对象与面向过程有什么区别

2.2、面向对象有哪些特征

2.3、面向对象开发方式有什么优点

2.4、多态的实现机制是什么

2.5、重载和覆盖有什么区别

2.6、抽象类和抽象接口有什么区别

2.7、内部类有哪些

3、关键字

3.1、assert有什么作用

3.2、static关键字有哪些作用

3.3、volatile有什么作用

3.4、instanceof有什么作用

3.5、strictfp有什么作用

4、基本类型与运算

4.1、java提供了哪些基本数据类型

4.2、什么是不可变类

4.3、值传递与引用传递有哪些区别

4.3、Math类中round、ceil和floor方法的功能是什么

4.4、char类型变量中是否可以存储一个中文汉字


1、基本概念

1.1、java语言有哪些优点

      1.java为纯面向对象的语言。它能够直接反应现实生活中的对象,例如火车动物等,因此通过它,开发人员编写程序更为容易。

      2.平台无关性。

      3.java提供了很多内置的类库,通过这些类库,简化了开发人员的程序设计工作,同时缩短了项目的开发时间。

      4.提供了对web应用开发的支持。例如,Applet、Servlet和JSP可以用来开发Web应用程序;Socket、RMI可以用来开发分布式应用程序的类库。

      5.具有较好的安全性和健壮性。java语言经常被用在网络环境中,为了增强程序的安全性,java语言提供了一个防止恶意代码攻击的安全机制(数组边界检测和Bytecode校验等)。java的强类型机制、垃圾回收器、异常处理和安全检查机制使得用java语言编写的程序有很好的健壮性。

      6.去除了c++语言中难以理解、容易混淆的特性,例如头文件、指针、结构、单元、运算符重载、虚拟基础类、多重继承等,使得程序更加严谨、简洁。

1.2、java与c/c++有何异同

      java和c++都是面向对象语言,都使用了面向对象思想(封装、继承、多态),由于面向对象有许多非常好的特性(继承、组合等),因此二者都有很好的可重用性。

不同点:

      1.java为解释型语言,其运行过程是:程序源码经过java编译器编译成字节码,然后由JVM解释执行。而c/c++为编译型语言,源代码经过编译和链接后生成可执行的二进制代码。因此,java的执行速度比c/c++慢,但是java能够跨平台执行。

      2.java为纯面向对象语言,所有代码必须在类中实现,除基本数据类型外,所有类型都是类。此外,java语言中不存在全局变量或全局函数,而c++兼具面向过程和面向过程编程的特点,可以定义全局变量和全局函数。

      3.与c/c++语言相比,java语言中没有指针的概念,这有效防止了c/c++语言中操作指针可能引起的系统问题,从而使程序变得更加安全。

      4.与c++语言相比,java语言不支持多重继承,但是java语言引入了接口的概念,可以同时实现多个接口。由于接口也具有多态特性,因此在java语言中可以通过实现多个接口来实现与c++语言中多重继承类似的目的。

      5.在c++语言中,需要开发人员去管理对内存的分配(包括申请和释放),而java语言提供了垃圾回收器来实现垃圾的自动回收,不需要程序显式的管理内存的分配。在c++语言中,通常会把释放资源的代码放到析构函数中,java语言中虽然没有析构函数,但却引入了一个finalize()方法,当垃圾回收器将要释放无用对象的内存时,会首先调用该对象的finalize()方法,因此,开发人员不需要关心也不需要知道对象所占的内存空间何时会被释放。

1.3、为什么需要public static void main(String[] args)这个方法

      这是java程序的入口方法,JVM在运行程序时会首先查找main()方法。main是JVM识别的特殊方法名,是程序的入口方法。字符串数组参数args为开发人员在命令行状态下与程序交互提供了一种手段。

      无论何种定义方式,都必须保证main()方法的返回值是void,并有static和public关键字修饰。同时由于main()方法为程序的入口方法,因此不能用abstract关键字来修饰。虽然每个类中都可以定义main()方法,但是只有与文件名相同的用public修饰的类中的main()方法才能作为整个程序的入口方法。

1.4、如何实现在main方法执行前输出“Hello World”

      在java语言中,由于静态块在类被加载时就会被调用,因此可以在main()方法执行前,利用静态块实现输出“Hello World”的功能。

public class Test{

      static{

            System.out.println("Hello World1");      //a

      }

      public static void main(String[] args){

             System.out.println("Hello World2");       //b

     }

}

由于静态块不管顺序如何,都会在main()方法执行之前执行,因此a,b无论顺序如何,都会有相同的输出结果。

1.5、java程序初始化的顺序是怎样的

      在java语言中,当实例化对象时,对象所在类的所有成员变量首先要进行初始化,只有当所有类成员变量完成初始化后,才会调用对象所在类的构造函数创建对象。

      java程序的初始化一般遵循三个原则(优先级依次递减):1:静态对象(变量)优先于非静态对象(变量)初始化,其中,静态对象(变量)只初始化一次,而非静态对象(变量)可能会初始化多次;2:父类优先于子类进行初始化;3:按照成员变量的定义顺序进行初始化,即使变量定义散布于方法定义之中,它们依然在任何方法(包括构造函数)被调用之前先初始化。

      java程序初始化工作可以在许多不同的代码块中来完成(例如静态代码块、构造函数等),它们执行的顺序如下:父类静态变量、父类静态代码块、子类静态变量、子类静态代码块、父类非静态变量、父类非静态代码块、父类构造函数、子类非静态变量、子类非静态代码块、子类构造函数。

1.6、java中的作用域有哪些

      在家吧语言中,变量的类型有3种:成员变量、静态变量和局部变量。

public:表明该成员变量或方法对所有类或对象都是可见的,所有类或对象都可以直接访问。

private:表明该成员变量或方法对该类是私有的,只有当前类对其具有访问权限。

protected:表明成员变量或方法对该类自身,与它在同一个包中的其他类,与其他包中的该类的子类都可见。

default:表明该成员变量或方法只有自己和与其在通过包内的类可见。若父类与子类位于同一个包内,则子类对父类的default成员变量或方法都有访问权限;若父类与子类位于不同的包内则没有访问权限。

1.7、一个java文件中是否可以定义多个类

      一个java文件可以定义多个类,但是最多只能有一个类被public修饰,并且这个类的类名与文件名相同,若这个文件没有public的类,则文件名随便是一个类的名字即可。

1.8、什么是构造函数

      构造函数是一种特殊的函数,用来在对象实例化时初始化对象的成员变量。在JAVA语言中,构造函数有以下特点:

      1、构造函数必须与类的名字相同,并且不能有返回值。

      2、每个类可以有多个构造函数。当开发人员没有提供构造函数时,编译器在把源代码编译成字节码的过程中会提供一个没有参数默认的构造函数,但该构造函数不会执行任何代码。如果开发人员提供了构造函数,那么编译器就不会创建默认的构造函数了。

      3、构造函数可以有0个、1个或一个以上的参数。

      4、构造函数总是伴随着new操作一起调用,且不能由程序的编写者直接调用,必须要由系统调用。构造函数在对象实例化时会被自动调用,且只运行一次;而普通的方法是在程序执行到它时被调用,且可以被该对象调用多次。

      5、构造函数的主要作用是完成对象的初始化工作。

      6、构造函数不能被继承,因此,他不能被覆盖,但是构造函数可以被重载,可以使用不同的参数个数或参数类型来定义多个构造函数。

      7、子类可以通过super关键字来显式的调用父类的构造函数,当父类没有提供无参数的构造函数时,子类的构造函数中必须显式的调用父类的构造函数。如果父类提供了无参数的构造函数,此时子类的构造函数就可以不显式的调用父类的构造函数,在这种情况下编译器会默认调用父类提供的无参数的构造函数。当有父类时,在实例化对象时会先执行父类的构造函数,然后执行子类的构造函数。

      8、当父类和子类都没有定义构造函数时,编译器会为父类生成一个默认的无参数的构造函数,给子类也生成一个默认的无参数的构造函数。此外,默认构造器的修饰符只跟当前类的修饰符有关。

1.9、为什么java中有些接口没有任何方法

      由于java不支持多重继承,即一个类只能有一个父类,为了克服单继承的缺点,java语言引入了接口这一概念。解口是抽象方法定义的集合(接口中也可以定义一些常量值),是一种特殊的抽象类。接口中只包含方法的定义,没有方法的实现。接口中的所有方法都是抽象的。接口中成员的作用域修饰符都是public,接口中的常量值默认使用public static final修饰。由于一个类可以实现多个接口,因此通常可以采用实现多个接口的方式来间接达到多重继承的目的。

      在java语言中,有些接口内部没有声明任何方法,也就是说,实现这些接口的类不需要重写任何方法,这些没有任何方法声明的接口又被叫做标识接口,标识接口对实现它的类没有任何语义上的要求,他仅仅充当一个标识的作用,用来表明实现它的类属于一个特定的类型。这个标签类似于汽车的标志图标,每当人们看到一个汽车的标志图标时就能知道这款汽车的品牌。java类库中已存在的标识接口有Cloneable和Serializable等。在使用时会经常用instanceof来判断实例对象的类型是否实现了一个给定的标识接口。

1.10、java中的clone方法有什么作用

      java在处理基本数据类型时都是采用按值传递(传输的是输入函数的复制)的方式执行,除此之外的其他类型都是按引用传递(传递的是一个对象的引用)的方式执行。对象除了在函数调用时是引用传递,在使用“=”赋值时也采用引用传递。clone()方法的作用是返回一个Object对象的复制。这个复制函数返回的是一个新的对象,而不是一个引用。

1.11、什么是反射机制

      反射机制是java语言中一个非常重要的特性,它允许程序在运行时进行自我检查,同时也允许对其内部的成员进行操作。由于反射机制能够实现在运行时对类进行装载,因此能够增加程序的灵活性,但是不恰当的使用反射机制也会严重影响系统的性能。

      具体而言,反射机制提供的主要功能有:得到一个对象所属的类;获取一个类的所有成员变量和方法;在运行时创建对象;在运行时调用对象的方法。

      总共有以下三种方法可以获取到class类:1:Class.forName(“类的路径”)2:类名.Class 3:实例.getclass()

      java创建对象的方式:1:通过new语句实例化一个对象;2:通过反射机制创建对象;3:通过clone()方法创建一个对象;4:通过反序列化的方式创建对象。

1.12、package有什么作用

      第一,提供多层命名空间,解决命名冲突,通过使用package,使得处于不同package的类可以存在相同的名字。第二、对类按功能进行分类,使项目的组织更加清晰。当开发一个有非常多类的项目时,如果不使用package对类进行分类,这样的代码不仅可读性差,而且可维护性也不好,会严重影响开发效率。

1.13、如何实现类似于c语言中函数指针的功能

      可以利用接口和类来实现这个效果。具体而言,先定义一个接口,然后在接口中声明要调用的方法,接着实现这个接口,最后把实现类的一个对象作为参数传递给调用程序,调用程序通过这个参数来调用指定的函数,从而实现回调函数的功能。

2、面向对象技术

2.1、面向对象与面向过程有什么区别

      1、出发点不同。面向对象方法是用符合常规思维的方式来处理客观世界的问题,强调把问题域的要领直接映射到对象及对象之间的接口上。而面向过程方法强调的是过程的抽象化与模块化,它是以过程为中心构造和处理客观世界问题的。

      2、层次逻辑关系不同。面向对象方法是用计算机逻辑来模拟客观世界中的物理存在,以对象的集合类作为处理问题的基本单位,尽可能的使计算机世界向客观世界靠拢,以使问题的处理更加清晰直接,面向对象方法是用类的层次结构来体现类之间的继承和发展。而面向过程方法处理问题的基本单位是能清晰准确的表达过程的模块,而模块的层次结构概括模块或模块间的关系和功能,把客观世界的问题抽象成计算机可以处理的过程。

      3、数据处理方式和控制程序方式不同。面向对象方法将数据与对应的代码封装成一个整体,原则上其他对象不能直接修改其数据,即对象的修改只能有自身的成员函数完成,控制程序方式上是通过“事件驱动”来激活和运行程序。而面向过程方法是直接通过程序来处理数据,处理完毕后即可显示处理结果,而控制程序方式上是按照设计调用或返回程序,不能自由导航,各模块之间存在着控制与被控制、调用与被调用的关系。

      4、分析设计与编码转换方式不同。面向对象方法贯穿于软件声明周期的分析、设计及编码中,是一种平滑过程,从分析到设计再到编码是采用一致性的模型表示,则实现的是一种无缝连接。而面向过程方法强调分析、设计及编码之间按规则进行转换,贯穿于软件生命周期的分析、设计及编码中,实现的是一种有缝连接。

2.2、面向对象有哪些特征

      1、抽象。抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分的注意与当前目标有关的方面。

      2、封装。封装是指将客观事物抽象成类,每个类对自身的数据和方法实行保护。类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

      3、继承。派生类从父类继承方法和实例变量。

      4、多态。多态是指允许不同类的对象对同一消息做出相应。多态包括参数化多态和包含多态。

2.3、面向对象开发方式有什么优点

      1、较高的开发效率;

      2、保证软件的鲁棒性。(较高的重用性,开发过程中可以重用已有的而且在相关领域经过长期测试的代码)

      3、保证软件的高可维护性。

2.4、多态的实现机制是什么

      1、方法的重载:重载是指同一个类中有多个重名的方法,但这些方法有着不同的参数,因此在编译时就可以确定到底要调用哪个方法,它是一种编译时多态。

      2、方法的覆盖:子类可以覆盖父类的方法,因此同样的方法会在父类和子类中有着不同的表现方式。在java语言中,基类的引用变量不仅可以指向基类的实例对象,也可以指向其子类的实例对象。同样接口的引用变量也可以指向其实现类的实例对象。而程序调用的方法在运行期才动态绑定(绑定指的是将一个方法调用和一个方法主体连接到一起)。由于只有在运行时才能确定调用哪个方法,因此通过方法覆盖实现的多态也可以被称为运行时多态。

2.5、重载和覆盖有什么区别

      重载:1、重载是通过不同的方法参数来区分的,例如不同的参数个数、不同的参数类型或不同的参数顺序。2、不能通过方法的访问权限、返回值类型和抛出的异常类型来进行重载。3、对于继承来说,如果基类方法的访问权限是private,那么就不能在派生类对其重载;如果派生类也定义了一个同名的函数,这只是一个新的方法,不会达到重载的效果。

      覆盖:1、派生类的覆盖方法必须和基类中被覆盖的方法有相同的函数名和参数。2、派生类中的覆盖方法必须和基类中被覆盖方法的返回值相同。3、派生类中的覆盖方法与抛出的异常必须和基类(或是其子类)中被覆盖方法所抛出的异常一致。4、基类中被覆盖的方法不能为private,否则其子类只是定义了一个方法,并没有对其覆盖。

      区别:1、覆盖是子类和父类之间的关系,是垂直关系;重载是同一个类中方法之间的关系,是水平关系。2、覆盖只能由一对方法产生关系;重载是多个方法之间的 关系。3、覆盖要求参数列表相同;重载要求参数列表不同。4、覆盖关系中,调用方法体是根据对象的类型(对象对应存储空间类型)来决定;而重载关系是根据调用时的实参表与形参表来选择方法体的。

2.6、抽象类和抽象接口有什么区别

      抽象类和接口都是支持抽象类定义的两种机制 。

      相同点:1、都不能被实例化;2、接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能被实现。

      不同点:

      1、接口只有定义,其方法不能在接口中实现,只有实现了接口的类才能实现接口中定义的方法,而抽象类可以有定义与实现,即其方法可以在抽象类中被实现。

      2、接口需要实现,但抽象类只能被继承。一个类可以实现多个接口,但一个类只能继承一个抽象类,因此使用接口可以间接达到多重继承的目的。

      3、接口强调特定功能的实现,其设计理念是“has a”关系,而抽象类强调所属关系,其设计理念是“is a”关系。

      4、接口中定义的成员变量默认为public static final,只能够有静态的不能被修改的数据成员,而且必须给其赋值,其所有成员方法都是public、abstract的,而且只能被这两个关键字修饰。而抽象类可以有自己的数据成员变量,也可以由非抽象的成员方法,而且抽象类中的成员变量默认为default,当然也可以定义为public,protected和private,这些成员变量可以在子类中被重新定义,也可以被重新赋值,抽象类中的抽象方法不能用private、static、synchronized、native等访问修饰符修饰,同时方法必须以分号结尾,并且不带花括号。

      5、接口被运用于实现比较常用的功能,便于日后维护或者添加删除方法;而抽象类更倾向于充当公共类的角色,不适用于日后重新对里面的代码进行修改。

2.7、内部类有哪些

      内部类主要有以下四种:静态内部类、成员内部类、局部内部类和匿名内部类。 

3、关键字

3.1、assert有什么作用

      断言作为一种软件调试的方法,提供了一种在代码中进行正确性检查的机制,目前很多开发语言都支持这种机制。它的主要作用是对一个boolean表达式进行检查,一个正确运行的程序必须保证boolean表达式的值为true,若为false则说明程序已经处于一种不正确的状态下,系统需要提供告警信息并退出程序。在实际的开发中,assert主要用来保证程序的正确性,通常在程序开发和测试时使用。为了提高程序运行的效率,assert检查默认是关闭的。

      assert包括两种表达式,分别是assert expression1和assert expression1:expression2,其中前者表示一个boolean表达式,后者表示一个基本类型或一个对象,基本类型包括:boolean,char,double,float,int和long。

3.2、static关键字有哪些作用

      static关键字主要有两种作用:第一,为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关。第二,实现某个方法或属性与类而不是对象关联在一起,也就是说,在不创建对象的情况下就可以通过类直接调用方法或使用类的属性。在java语言中,static主要有4中使用情况:成员变量,成员方法,代码块和内部类。

      1、static成员变量:java类提供了两种类型的变量:用static修饰的静态变量和不用static修饰的实例变量。静态变量属于类,在内存中只有一个复制(所有实例都指向同一个内存地址),只要静态变量所在的类被加载,这个静态变量就会被分配空间,因此就可以被使用了。

      2、static成员方法:与变量类似,java类同时也提供了static与非static方法。static方法是类的方法,不需要创建对象就可以被调用,而非static方法是对象的方法,只有对象被创建出来后才可以被使用。

      static方法中不能使用this和super关键字,不能调用非static方法,只能访问所属类的静态成员变量和成员方法,因为当static方法被调用时,这个类的对象可能还没被创建,即使已经被创建了,也无法确定调用哪个对象的方法。同理,static方法也不能访问非static类型的变量。

      3、static代码块:static代码块在类中是独立于成员变量和成员函数的代码块的。它不在任何一个方法体内,JVM在加载类时会执行static代码块,如果有多个static代码块,JVM将会按顺序来执行。static代码块经常被用来初始化静态变量。

      4、static内部类:它是指被声明为static的内部类,它可以不依赖于外部类实例对象而被实例化,而通常的内部类需要在外部类实例化之后才能实例化。静态内部类不能与外部类有相同的名字,不能访问外部类的普通成员变量,只能访问外部类的静态成员和静态方法(包括私有类型)。

3.3、volatile有什么作用

      volatile是一个类型修饰符,他是被设计用来修饰被不同线程访问和修改的变量。被volatile类型定义的变量,系统每次用到它时都是直接从对应的内存当中提取,而不会利用缓存。在使用volatile修饰的成员变量后,所有线程在任何时候所看到的变量的值都是相同的。

3.4、instanceof有什么作用

      它的作用是判断一个引用类型的变量所指向的对象是否是一个类(或接口、抽象类、父类)的实例,即它左边的对象是否是它右边的类的实例该运算符返回Boolean类型的数据。

3.5、strictfp有什么作用

      关键字是strict float point的缩写,指的是精确浮点,它用来确保浮点数运算的准确性。JVM在执行浮点数运算时,如果没有指定strictfp关键字,此时计算结果可能会不精确,而且计算结果在不同平台或厂商的虚拟机上会有不同的结果,导致意想不到的错误。而一旦使用strictfp来声明一个类、接口或方法,那么在所声明的范围内,java编译器以及运行环境会完全按照IEEE二进制浮点数算术标准(IEEE754)来执行,在这个关键字声明的范围内所有浮点数的计算都是准确的。需要注意的是,当一个类被strictfp修饰时,所有方法都会自动被strictfp修饰。因此,strictfp可以保证浮点数运算的精确性,而且在不同的硬件平台上会有一致的运行结果。

4、基本类型与运算

4.1、java提供了哪些基本数据类型

java语言一共提供了8种原始的数据类型(byte,short,int,long,float,double,char,boolean),这些数据类型不是对象,而是java语言中不同于类的特殊类型。这些基本类型的数据变量在声明之后就会立刻在栈上被分配内存空间。除了这8种基本的数据类型外,其他类型都是引用类型(例如类、接口、数组等),引用类型类似于c++中的引用或指针的概念,它以特殊的方式指向对象实体,这类变量在声明时不会被分配内存空间,只是存储了一个内存地址而已。

char(Unicode字符)占16bit。

      此外,java语言还提供了对这些原始数据类型的封装类(Character,Boolean,Byte,Short,Integer,Long,Float,Double)。需要注意的是,java中的数值类型都是有符号的,不存在无符号的数,它们的取值范围也是固定的,不会随着硬件环境或者操作系统的改变而改变。原始数据类型在传递参数时都是按值传递,而封装类型是按引用传递的。对象引用实例变量的默认值是null,而原始类型实例变量的默认值与它们的类型有关。

4.2、什么是不可变类

      不可变类是指当创建了这个类的实例后,就不允许修改它的值了,也就是说,一个对象一旦被创建出来,在整个声明周期中它的成员变量就不能被修改了。他有点类似于常量,即只允许别的程序读,不允许别的程序进行修改。

      在java类库中,所有基本类型的包装类都是不可变类。例如Integer,Float等。此外,String类也是不可变类。

4.3、值传递与引用传递有哪些区别

      java语言提供了两种参数传递的方式:值传递和引用传递。

      1、值传递:在方法调用中,实参会把他的值传递给形参,形参只是实参的值初始化一个临时的存储单元,因此形参与实参虽然有着相同的值,但是却有着不同的存储单元,因此对形参的改变不会影响实参的值。

      2、引用传递:在方法传递中,传递的是对象(也可以看做是对象的地址),这时形参与实参的对象指向同一块存储单元,因此对形参的修改就会影响实参的值。

      在java语言中,原始数据类型在传递参数时都是按值传递,而包装类型在传递参数时是按引用传递的。

4.3、Math类中round、ceil和floor方法的功能是什么

      这三个方法位于math类中,Math是一个包含了很多数学常量与计算方法的类,位于java.long包下,能自动导入,而且Math类里边的方法全是静态方法。

      1、round方法表示四舍五入。其原理是在原来数字基础上先增加0.5再向下取整,它的返回值类型是int型。

      2、ceil方法的功能是向上取整,就是取大于参数的最小的整数值。需要主要它的返回值类型是double。

      3、floor方法的功能是向下取整,就是对操作数取底,取小于参数的最大整数值,返回值也是double型。

4.4、char类型变量中是否可以存储一个中文汉字

      在java语言中,默认使用的Unicode编码方式,即每个字符占两个字节,因此可以存储中文。虽然String是由char所组成的,但是它采用了一种更加灵活的方式存储,即英文占用一个字符,中文占用两个字符,采用这种存储方式的一个重要作用是可以减少所需的存储空间,提高存储效率。

posted @ 2018-11-30 18:35  strawqqhat  阅读(195)  评论(0编辑  收藏  举报
#home h1{ font-size:45px; } body{ background-image: url("放你的背景图链接"); background-position: initial; background-size: cover; background-repeat: no-repeat; background-attachment: fixed; background-origin: initial; background-clip: initial; height:100%; width:100%; } #home{ opacity:0.7; } .wall{ position: fixed; top: 0; left: 0; bottom: 0; right: 0; } div#midground{ background: url("https://i.postimg.cc/PP5GtGtM/midground.png"); z-index: -1; -webkit-animation: cc 200s linear infinite; -moz-animation: cc 200s linear infinite; -o-animation: cc 200s linear infinite; animation: cc 200s linear infinite; } div#foreground{ background: url("https://i.postimg.cc/z3jZZD1B/foreground.png"); z-index: -2; -webkit-animation: cc 253s linear infinite; -o-animation: cc 253s linear infinite; -moz-animation: cc 253s linear infinite; animation: cc 253s linear infinite; } div#top{ background: url("https://i.postimg.cc/PP5GtGtM/midground.png"); z-index: -4; -webkit-animation: da 200s linear infinite; -o-animation: da 200s linear infinite; animation: da 200s linear infinite; } @-webkit-keyframes cc { from{ background-position: 0 0; transform: translateY(10px); } to{ background-position: 600% 0; } } @-o-keyframes cc { from{ background-position: 0 0; transform: translateY(10px); } to{ background-position: 600% 0; } } @-moz-keyframes cc { from{ background-position: 0 0; transform: translateY(10px); } to{ background-position: 600% 0; } } @keyframes cc { 0%{ background-position: 0 0; } 100%{ background-position: 600% 0; } } @keyframes da { 0%{ background-position: 0 0; } 100%{ background-position: 0 600%; } } @-webkit-keyframes da { 0%{ background-position: 0 0; } 100%{ background-position: 0 600%; } } @-moz-keyframes da { 0%{ background-position: 0 0; } 100%{ background-position: 0 600%; } } @-ms-keyframes da { 0%{ background-position: 0 0; } 100%{ background-position: 0 600%; } }