It is both a class and a method. Cons is a type parametised class. List[A] has two sub classes: Cons and Nil. As Cons is a class it can be created by its constructor as follows:
val s = new ::[Int](4, Nil)
Cons is a case class and we use the constructor when we do a pattern match. Cons is also a method on the list class that is implemented in its two sub classes. Hence we can use the cons method on the cons class that we have created above.
val s1 = s.::(5)
Part of the confusion may arise, because we normally create Lists using the apply method of the List object:
val s2 = List(1, 2, 3)
Normally the apply method of an object returns a new instance of the Class with the same name as an object. This is however just convention. In this particular case the List Object returns a new instance of the Cons subclass. The List class itself is a sealed abstract class so can not be instantiated. So the above apply method does the following:
val s2 = 1 :: 2 :: 3 :: Nil
Any method that ends in a ':' is a method on the operand to its right so it can be rewritten as
val s2 = 1 :: (2 :: (3 :: Nil)) //or as
val s2 = Nil.::(3).::(2).::(1)
So the Cons(::) method on the Nil object takes the 3 as a parameter and produces an anonymous instantiation of the Cons class with 3 as its head and a reference to the Nil object as its tail. Lets call this anonymous object c1. The Cons method is then called on c1 taking 2 as its parameter returning a new anonymous Cons instantiation lets call it c2, which has 2 for its head and a reference to c1 as its tail. Then finally the cons method on the c2 object takes the 1 as a parameter and returns the named object s2 with 1 as its head and a reference to c2 as its tail.
A second point of confusion is that the REPL and Scala worksheets use a class' toString methods to display results. So the worksheet gives us:
val s3 = List(5, 6, 7) // s3 : List[Int] = List(5, 6, 7)
val s4 = List() // s4 : List[Nothing] = List()
val s5: List[Int] = List() // s5 : List[Int] = List()
s3.getClass.getName // res3: String = scala.collection.immutable.$colon$colon
s4.getClass.getName // res4: String = scala.collection.immutable.Nil$
s5.getClass.getName // res5: String = scala.collection.immutable.Nil$
As said above List is sealed so new sub sub classes can not be created as Nil is an object and Cons is final. As Nil is an object it can't be parametrised. Nil inherits from List[Nothing]. At first glance that doesn't sound that useful but remember these data structures are immutable, so we can never add to them directly and Nothing is a sub class of every other class. So we can add the Nil class (indirectly) to any List without problem. The Cons class has two members a head and another List. Its a rather neat solution when you clock it.
I'm not sure if this has any practical use but you can use Cons as a type:
var list: ::[Int] = List (1,2,3).asInstanceOf[::[Int]]
println("Initialised List")
val list1 = Nil
list = list1.asInstanceOf[::[Int]] //this will throw a java class cast exception at run time
println("Reset List")