I would read the Wiki article on this: http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)
I would say that encapsulation is basically the idea that you are "hiding" the details of the operations from the "user". OK, so for instance, let's say you implement a Stack object. The encapsulation means that you the "user" only sees TWO basic functions:
void push(T element);
and
T pop();
This is the encapsulation. There is A LOT of stuff underlying HOW you manage to achieve this action (for instance you probably use a Linked List)--but the "user" has NO knowledge of these lower-level details--all the "user" knows is that you can add to the stack (through push) and retrieve from the stack through pop.
(I use quotes around user because the "user" is really the programmer using your class--NOT the end user--there is a difference...although if you are creating libraries then the end user IS a programmer).
Information hiding is a different thing (as has been stated). Information hiding to me, has more security implications--but I GUARANTEE you that this is NOT well understood (at least with Java). Here is a general idea:
You have an object that has internal members (fields). When the object changes, this means the member fields change. Generally though, objects have a set way that its fields should change to maintain a "sane" state (i.e. a state where the object is still correct or even just maintaining proper functioning). Generally speaking, this is why you should ONLY modify an object through method calls RATHER than modifying the fields of an object directly. This is because the method calls modify the object in the way that you WANT it to be modified while modifying fields directly might have unintended consequences.
Now unfortunately, this is somewhat of a contrived notion. 1) if you "abuse" and object you should NOT be surprised when it malfunctions (so don't do things if you DON'T understand what's going on) and 2) even with method calls you can STILL mess up an object pretty royally.
First, here's an example of what I mean by "abusing" an object: here is a Stack class which uses a Node class (you'll have to infer the fields of the Node class--so I hope you are familiar with linked lists):
Stack class: http://ideone.com/getiYc
Now, notice that I declared head as public. This means that EVERY other class has DIRECT access to modify head. Now, that's FINE if say, I declare another class which is supposed to clear the Stack:
public class StackClearer{
public static void clearStack(Stack stack){
stack.head = null;
}
}
See, it's nice to have the head declared as public because I understand the low-level operations and this provides an easy way to clear the stack (granted, this should probably just be a method of the Stack class). BUT, what if I am stupid and DON'T understand how a stack works. Then I might do something like this:
public class ImStupid{
public static void messUpStack(Stack
stack){
stack.head = new Node("I totally messed up");
}
}
I've completely messed up my Stack--it NO LONGER holds ANY of the things it used to hold--so if another class is allowed to do this, then they might mess up the sanity of my Stack object. This is why information hiding is important--it PREVENTS the programmer from messing up the state of the object. Instead, ONLY call methods and that way, the object ALWAYS remains sane.
So now let's see why I say this is complicated. Let's say that I have a class which maintains ordered pairs of integers and strings:
OrderPairs class: http://ideone.com/47m8V0
Now this is pretty reasonable for a beginning (and even advanced) programmer to write. You CERTAINLY would like to be able to get the set of available keys (i.e. the getKeys() method), but HERE is the problem. Because you return a non-primitive (an object) you allow for the programmer to MESS UP the sanity of your object. It's simple:
public class Tester{
public static void main(String ...args){
final OrderPairs op = new OrderedPairs();
op.addPair(0, "hello");
op.addPair(3, "goodbye");
final ArrayList keys = op.getKeys();
keys.clear();
op.addPair(1, "oops");
System.out.println("value of key = 1 is " + op.getValue(1));
}
}
What do you think the above should print? Because it will print "hello" for the value, NOT "oops". By returning an object (that is NOT immutable) you have allowed the programmer to mess up the internal representation of the object.